Парсинг целевой аудитории ВКонтакте
При размещении рекламы некоторые площадки в настройках аудитории позволяют загрузить список конкретных людей, которые увидят рекламу. Для парсинга id по конкретным пабликам существуют специальные инструменты, но куда интереснее (и дешевле) сделать это собственноручно при помощи Python и VK API. Сегодня расскажем, как для рекламной кампании LEFTJOIN мы спарсили целевую аудиторию и загрузили её в рекламный кабинет.
В материале «Собираем данные по рекламным кампаниям ВКонтакте» подробно описан процесс получения токена пользователя для VK API
Парсинг пользователей
Для отправки запросов потребуется токен пользователя и список пабликов, чьих участников мы хотим получить. Мы собрали около 30 сообществ, посвящённых аналитике, BI-инструментам и Data Science.
import requests import time group_list = ['datacampus', '185023286', 'data_mining_in_action', '223456', '187222444', 'nta_ds_ai', 'business__intelligence', 'club1981711', 'datascience', 'ozonmasters', 'businessanalysts', 'datamining.team', 'club.shad', '174278716', 'sqlex', 'sql_helper', 'odssib', 'sapbi', 'sql_learn', 'hsespbcareer', 'smartdata', 'pomoshch_s_spss', 'dwhexpert', 'k0d_ds', 'sql_ex_ru', 'datascience_ai', 'data_club', 'mashinnoe_obuchenie_ai_big_data', 'womeninbigdata', 'introstats', 'smartdata', 'data_mining_in_action', 'dlschool_mipt'] token = 'ваш_токен'
Запрос на получение участников сообщества к API ВКонтакте вернёт максимум 1000 строк — для получения последующих тысяч потребуется смещать параметр offset на единицу. Но нужно знать, до какого момента это делать — поэтому опишем функцию, которая принимает id сообщества, получает информацию о числе участников сообщества и возвращает максимальное значение для offset — отношение числа участников к 1000, ведь мы можем получить ровно тысячу человек за раз.
def get_offset(group_id): count = requests.get('https://api.vk.com/method/groups.getMembers', params=< 'access_token':token, 'v':5.103, 'group_id': group_id, 'sort':'id_desc', 'offset':0, 'fields':'last_seen' >).json()['response']['count'] return count // 1000
Следующим этапом опишем функцию, которая принимает id сообщества, собирает в один список id всех подписчиков и возвращает его. Для этого отправляем запросы на получение 1000 человек, пока не кончается offset, вносим данные в список и возвращаем его. Проходя по каждому человеку дополнительно проверяем дату его последнего посещения социальной сети — если он не заходил с середины ноября, добавлять его не будем. Время указывается в формате unixtime.
def get_users(group_id): good_id_list = [] offset = 0 max_offset = get_offset(group_id) while offset < max_offset: response = requests.get('https://api.vk.com/method/groups.getMembers', params=< 'access_token':token, 'v':5.103, 'group_id': group_id, 'sort':'id_desc', 'offset':offset, 'fields':'last_seen' >).json()['response'] offset += 1 for item in response['items']: try: if item['last_seen']['time'] >= 1605571200: good_id_list.append(item['id']) except Exception as E: continue return good_id_list
Теперь пройдём по всем сообществам из списка и для каждого соберём участников, а затем внесём их в общий список all_users. В конце переводим сначала список в множество, а затем опять в список, чтобы избавиться от возможных дубликатов: одни и те же люди могли быть участниками разных пабликов. Лишним не будет после каждого паблика приостановить работу программы на секунду, чтобы не столкнуться с ограничениями на число запросов.
all_users = [] for group in group_list: print(group) try: users = get_users(group) all_users.extend(users) time.sleep(1) except KeyError as E: print(group, E) continue all_users = list(set(all_users))
Последним шагом записываем каждого пользователя в файл с новой строки.
with open('users.txt', 'w') as f: for item in all_users: f.write("%s\n" % item)
Аудитория в рекламном кабинете из файла
Переходим в свой рекламный кабинет ВКонтакте и заходим во вкладку «Ретаргетинг». Там будем кнопка «Создать аудиторию»:
После нажатия на неё откроется новое окно, где можно будет выбрать в качестве источника файл и указать название для аудитории:

После загрузки пройдёт несколько секунд и аудитория будет доступна. Первые минут 10 будет указано, что аудитория слишком мала: это не так и панель вскоре обновится, если в вашей аудитории действительно более 100 человек.

Итоги
Сравним среднюю стоимость привлечённого в наше сообщество участника в объявлении с автоматической настройкой аудитории и в объявлении, аудиторию для которого мы спарсили. В первом случае получаем среднюю стоимость в 52,4 рубля, а во втором — в 33,2 рубля. Подбор качественной аудитории при помощи методов парсинга данных из ВКонтакте помог снизить среднюю стоимость на 37%.
Для рекламной кампании мы подготовили такой пост (нажмите на картинку, чтобы перейти к нему):
Парсинг данных через api vk и google sheets api на python
Появилась потребность собирать статистику постов из группы в контакте и затем проанализировать реакции подписчиков на конкретные посты. Если переформулировать на выходе стоит задача с заданной периодичностью снимать показания статистики постов в вк и сохранять их.
Я не профессиональный программист и не претендую, поэтому решил сделать все довольно просто. При помощи api VK забирать посты из группы, собираю нужный мне датафрейм и записываю данные в гугл таблицу, так же через api.
Может быть это и не самое оптимальное решение,

Настраиваем API VK
В этом блоке мы хотим собрать статистику постов из группы vk.
Для начала работы нам нужен user_token из vk. Мне понравилась видеоинструкция здесь, коротко и по делу.
Токен держим в секрете. Переходим в https://dev.vk.com изучаем документацию API.
Прямо на сайте документации можем попробовать дернуть запрос.
Для этого нам нужно access_token, domain, count, v, filter.
access_token – получили на прошлом шаге. domain – название группы вы увидите в url название группы например https://vk.com/adminsclub. count – количество постов которые можем дернуть. v – версия api. filter – хотим получить только посты от группы устанавливаем owner.
Прописываем логику сбора
Импортируем библиотеку requests. Дергаем тестовый запрос. Поcле анализа структуры решаю, что мне нужен раздел items
# переменные TOKEN_USER = #ваш токен VERSION = #версися api vk DOMAIN = #ваш domain # через api vk вызываем статистику постов response = requests.get('https://api.vk.com/method/wall.get', params=) data = response.json()['response']['items']
Отдельное поле в статистики количество фотографий для поста, я не нашел.
Через цикл перебираем каждый пост и считаем количество фото, если фотографии нет скрипт ловит ошибку. Обрабатываем ошибку и ставим 0. Собираем новый список с полями id поста и количество фото.
Пишем обработчик. Вызываем pandas
# считаем сколько фото у поста, заводи все в df id = [] photo = [] for post in data: id.append(post['id']) try: photo.append(len(post['attachments'])) except: photo.append(0) df_photo = pd.DataFrame( )
Переводим cловарь в df. Импортируем метод from pandas import json_normalize
Оставляем нужные атрибуты и переводим дату в другой формат.
В переменной post_id запихиваем id наших постов.
Я бы хотел обогатить свою статистику более расширенными измерениями
Из документации по api о которой рассказывал выше подобрал метод status.getPostReach
В методе обнаружил новый аргумент owner_id, его можно найти в настройках группы.
Делаем еще один запрос и новые данные сохраняем в датафрейм df_stat_post
# вытаскиваем нужные нам столбцы и переводим формат даты df = json_normalize(data) df = df[['id','date','comments.count','likes.count','reposts.count','reposts.wall_count','reposts.mail_count','views.count','text']] df['date']= [datetime.fromtimestamp(df['date'][i]) for i in range(len(df['date']))] # для каждого поста вытаскиваем дополнительную статистику post_id = ','.join(df['id'].astype("str")) response = requests.get('https://api.vk.com/method/stats.getPostReach', params=) data = response.json()['response'] df_stat_post = json_normalize(data)
Теперь приступим к сборке объединяем все наши датафреймы, накидываем дополнительные метрики.
Далее наши данные преобразовываем для загрузки в гугл таблицу.
# объединяем все df cо всеми статистиками и количествам фото df_final = df.merge(df_stat_post, how='left', left_on='id', right_on="post_id") df_final = df_final.merge(df_photo, how='left', left_on='id', right_on="id") df_final.drop(columns='post_id',inplace=True) # добавляем дополнительные столбцы с временем df_final['date_time_report'] = datetime.now() df_final['date_report'] = date.today() df_final['year'] = df_final['date_time_report'].dt.year df_final['month'] = df_final['date_time_report'].dt.month df_final['day'] = df_final['date_time_report'].dt.day df_final['hour'] = df_final['date_time_report'].dt.hour df_final['minute'] = df_final['date_time_report'].dt.minute df_final[['date','date_report','date_time_report']] = df_final[['date','date_report','date_time_report']].astype('str') # сохраняем все значения data_list = df_final.values.tolist()
Грузим в google sheet через api
Есть готовые библиотеки для работы с google sheet например pygsheets, но мне было важно поработать с API поэтому легких путей не искал.
Прежде чем загрузить надо настроить наш api прекрасная статья, в который пошагово написано и даст возможность поиграться с листами https://habr.com/ru/post/483302/
# подключаемся к гугл таблице CREDENTIALS_FILE = # Имя файла с закрытым ключом, вы должны подставить свое # Читаем ключи из файла credentials = ServiceAccountCredentials.from_json_keyfile_name(CREDENTIALS_FILE, ['https://www.googleapis.com/auth/spreadsheets', 'https://www.googleapis.com/auth/drive']) httpAuth = credentials.authorize(httplib2.Http()) # Авторизуемся в системе service = apiclient.discovery.build('sheets', 'v4', http = httpAuth) # Выбираем работу с таблицами и 4 версию API spreadsheetId = # ваш id лист
После подключения к листу. Находим последнюю заполненную строку.
В моем примере я заполняю последние 10 строк ровно по количеству постов которые я получил из get запроса. Подготавливаем шаблон для запроса, заполняем шаблон данными какие ячейки заполняем и заполняем. Далее выполняем запрос. Готово
# находим последнию строку заполненную response = service.spreadsheets().values().get(spreadsheetId = spreadsheetId,range="Лист номер один!A1:A").execute() # последние 10 строк заполняем number_sheet = "Лист номер один!A" + str(len(response['values'])+1) + ':AA' + str(len(response['values'])+10) # создаем запрос и вставляем туда данные data_vk = < "valueInputOption": "USER_ENTERED", # Данные воспринимаются, как вводимые пользователем (считается значение формул) "data": [ ] > data_vk['data'][0]['range'] = number_sheet data_vk['data'][0]['values'] = data_list # выполняем запрос results = service.spreadsheets().values().batchUpdate(spreadsheetId = spreadsheetId, body = data_vk).execute()
Заключение
После написания этого кода мне требовалось запускать его каждый час и принял решение арендовать сервер, установить туда docker и через crontab запускать.
Пишем простой парсер ВК на Python
Парсер — программа, которая по заданному алгоритму собирает нужную информацию на сайте. Парсеры часто применяют в маркетинговых целях, чтобы собрать базу для таргетированной рекламы или спам рассылки. Наш парсер будет способен формировать базу участников выбранного сообщества, сохранять базы в txt файле, высчитывать процент пересечения двух баз, объединять две базы в одну без повторов, а также будет доступен ввод сохраненной базы из txt файла.
Подготовка
Для взаимодействия с API Вконтакте мы будем использовать модуль vk. Установить vk можно через pip с помощью команды: pip install vk
Также, чтобы получить сервисный ключ доступа, нам потребуется создать приложение на сайте Вконтакте. Это можно сделать по этой ссылке.
Пишем код
Первым делом давайте импортируем модуль vk, обозначим имена наших будущих функций и напишем авторизацию.
Проблема заключается в том, что этот метод может возвратить нам максимум 1000 id’шников. Но благодаря параметру offset, который отвечает за смещение от начала полного списка участников(по умолчанию 0), и циклу for, мы можем получить список всех участников сообщества.
На этом все! При желании, немного изменив код, можно собирать больше информации о пользователях.
Automated posting on Vkontakte public pages using VK API and Python


Vk.com (Vkontakte) is the most popular social network Russia and Ex-USSR with 430+ million users. Traditional advantages of vk.com – huge amount of free music and video. The service allows users to upload and share files and for a long time was quite tolerant to piracy. In 2016 Mail.Ru Group, Vkontakte parent company, has solved all problems with major music labels and now works closely with the rights holders.
VKontakte has very efficient features for creating communities: public pages (blogs) and groups (open and closed web-forums). In VK communities you can easily share news, photo, audio, video, text files in different formats, create discussions topics and wiki-pages. When I was studying at the University in 2003-2009, to share information in a study group we needed to create our own website and phpBB-based forum. Now practically all students simply use VKontakte groups for this. VKontakte shows all content in groups as is, without hiding and filtering.
With reach automation capabilities, you can do various interesting things based on VK. For a start, I decided to post all annotations from my https://avleonov.com blog to https://vk.com/avleonovcom Vkontakte page. I created this page in web GUI and filled it with content automatically using my own python scripts.
Creating a new application
I want to work with Vkontakte from my Python scripts. So, I will need to create a new Standalone Application for this. You can do it here: https://vk.com/editapp?act=create

Upd. March 2018 Integration with Vkontakte suddenly broke, because they added mandatory version parameter to all calls.

Getting sms code for confirmation. And now I have a new application:

I changed status to “Application on and visible to all”.
Getting page info
Now let’s try to do something. All available methods are listed at https://vk.com/dev/methods
For most of the methods token authentication required. For example, using community token, you can do some operations on your page. Let’s get it. I go to the page https://vk.com/avleonovcom?act=tokens
Select required rights for a new access token:
- Allow the application to control the community
- Allow access to community messages
- Allow access to community photos
- Allow access to community documents
Getting sms code for confirmation. And now I have a token:

Now let’s get information about the group:
#!/usr/bin/python import community_token = "3bXXXXXXXXXXXXXXXXa3" params = ( ('group_id', 'avleonovcom'), ('access_token', community_token), ) response = requests.get('https://api.vk.com/method/groups.getById', params=params) print(response.text)
Response in Json:
Creating a post
Ok, now let’s see how to post something on a community wall https://vk.com/dev/wall.post
For this I need user token. I will try “Implicit Flow” for User Access Token.
I simply open this url in browser:
https://oauth.vk.com/authorize?client_id=6096665&display=page&redirect_uri=https://oauth.vk.com/blank.html&scope=offline,photos,wall,groups&response_type=token&v=5.65

And when I press “Allow” I will be redirected to:
https://oauth.vk.com/blank.html#access_token=bd9487fcd4bd6de7e43aqjfo2n3tjdfi3323b6327b1128987c834ab0b13d8a2fbe1fedc0119bcb4762d2a49&expires_in=0&user_id=1468099
And now can use this token.
Note! “-” in owner_id. It’s important!
user_token = "bdXXXXXXXXXXXXXXXX49" params = ( ('owner_id', '-149273431'), ('from_group', '1'), ('message', 'Hello world!'), ('access_token', user_token), ) response = requests.get('https://api.vk.com/method/wall.post', params=params) print(response.text)

First automatically posted message! Great!
Ok, now let’s try to post url with some text and photo
params = ( ('owner_id', '-149273431'), ('from_group', '1'), ('message', 'Hello world2!'), ('message', 'photo1468099_456239095,https://avleonov.com'), ('access_token', user_token), ) response = requests.get('https://api.vk.com/method/wall.post', params=params) print(response.text)

All necessary elements are here: multiline, hashtags, urls and pictures. It’s a pitty that I can’t specify image for any url, like I can do it in GUI.
As you see, I have used picture ID photo1468099_456239095 from my personal page. So, let’s also see how to add pictures to the community page.
Creating a new photo album
First of all, I need a photo album at my page. I can create it manually or use this method https://vk.com/dev/photos.createAlbum
params = ( ('group_id', '149273431'), ('title', 'blog illustrations'), ('description', 'images from avleonov.com'), ('upload_by_admins_only', '0'), ('comments_disabled', '0'), ('access_token', user_token), ) response = requests.get('https://api.vk.com/method/photos.createAlbum', params=params) print(response.text)
Ok, here is my new album:
Now let’s add images to this album.
Uploading images
First of all, I need to ask Vk what server I can use for uploading images in particular community and album: https://vk.com/dev/photos.getUploadServer
params = ( ('group_id', '149273431'), ('album_id', '245830662'), ('access_token', user_token), ) response = requests.get('https://api.vk.com/method/photos.getUploadServer', params=params) print(response.text)
Getting url from this json:
import json upload_server = json.loads(response.text)['response']['upload_url'] print(upload_server)
Now I can upload image file petya.png to the server using this url
files = response = requests.post(upload_server, files=files) print(response.text)
Getting necessary parameters:
img_hash = json.loads(response.text)['hash'] photos_list = json.loads(response.text)['photos_list'] server = json.loads(response.text)['server']
And finally save uploaded file to the photo album: https://vk.com/dev/photos.save
params = ( ('group_id', '149273431'), ('album_id', '245830662'), ('hash', img_hash), ('photos_list', photos_list), ('server', server), ('caption', 'test image'), ('access_token', user_token), ) response = requests.get('https://api.vk.com/method/photos.save', params=params) print(response.text)

Note! The server returns the ID photo1468099_456239022. This is my user ID. And the page ID is 149273431. I do not know why this ID is returned. So, I edit id with this substitution:
photo_id = re.sub("photo1468099", "photo-149273431", photo_id)
So, now we can add pictures to community photo album. We can make a post from the image identifier, text description and the web-link. This is enough to make a successful integration of your site with your Vkontakte page.
Note! There is a limit, you can create no more than 50 posts per day on the wall!

Hi! My name is Alexander and I am a Vulnerability Management specialist. You can read more about me here. Currently, the best way to follow me is my Telegram channel @avleonovcom. I update it more often than this site. If you haven’t used Telegram yet, give it a try. It’s great. You can discuss my posts or ask questions at @avleonovchat.
А всех русскоязычных я приглашаю в ещё один телеграмм канал @avleonovrus, первым делом теперь пишу туда.
