Основы программирования в Python

Работа с API ВКонтакте: продолжение

Алла Тамбовцева, НИУ ВШЭ

Выполняем операции, необходимые для работы с API ВКонтакте (см. предыдущую лекцию):

In [1]:
import vk
In [2]:
token = "" # введите Ваш токен
session = vk.Session(access_token = token)
api = vk.API(session)

Попробуем получить определенную информацию о пользователях, ту информацию, которая хранится в определенных полях (fields). Например, нас интересует пол пользователей, город проживания и данные по высшему образованию (институт/университет, факультет, отделение и прочее).

Берем метод users.get() и указываем id интересующих нас пользователей. Если числовой id неизвестен, достаточно имени пользователя в том виде, в каком мы его видим в ссылке на страницу с профилем. В списке с id могут быть элементы разных типов, как числовые id, так и текстовые имена одновременно:

In [3]:
api.users.get(user_ids = ['navasilyonok', 20473269], 
              v = 5.103, 
              fields = ['sex', 'city', 'universities'])
Out[3]:
[{'id': 171544496,
  'first_name': 'Наталья',
  'last_name': 'Василёнок',
  'is_closed': False,
  'can_access_closed': True,
  'sex': 1,
  'city': {'id': 1, 'title': 'Москва'},
  'universities': [{'id': 128,
    'country': 1,
    'city': 1,
    'name': 'НИУ ВШЭ (ГУ-ВШЭ)',
    'faculty': 475,
    'faculty_name': 'Факультет социальных наук',
    'chair': 2037672,
    'chair_name': 'Политология',
    'graduation': 2017,
    'education_form': 'Очное отделение',
    'education_status': 'Студентка (бакалавр)'}]},
 {'id': 20473269,
  'first_name': 'Алла',
  'last_name': 'Тамбовцева',
  'is_closed': False,
  'can_access_closed': True,
  'sex': 1,
  'city': {'id': 1, 'title': 'Москва'},
  'universities': [{'id': 128,
    'country': 1,
    'city': 1,
    'name': 'НИУ ВШЭ (ГУ-ВШЭ)',
    'graduation': 2016,
    'education_status': 'Студентка (бакалавр)'}]}]

Некоторые методы работают только с числовыми id. Как его получить с помощью API на основе текстового имени пользователя? Просто – запросить данные по пользователю и из списка с основной информацией извлечь значение поля 'id', что выглядит как извлечение значения по ключу из словаря:

In [4]:
id_ = api.users.get(user_ids = 'allatamb', v = 5.103)[0]['id']
id_
Out[4]:
20473269

Один из методов, который работает только с числовыми id – метод для получения списка друзей:

In [5]:
# friends.get() вернет словарь
# из него извлекаем список по ключу items

friends = api.friends.get(user_id = id_, v = 5.103)['items']

Выставим задержку по времени в 2 секунды, чтобы не делать частых запросов и не столкнуться с ошибкой, вызываемой ограничениями API по числу запросов в секунду, и запросим имена и фамилии друзей пользователя:

In [9]:
from time import sleep

for f in friends:
    user = api.users.get(user_ids = f, v = 5.103)[0]
    print(user['first_name'], user['last_name'])
    sleep(2) 
    
# это надолго, прервала исполнение этой ячейки
Валерий Окунев
Егор Юрескул
Антон Воробьев
Любовь Сысоева
Антон Клименков
Dmitry Ekhilevskiy
---------------------------------------------------------------------------
KeyboardInterrupt                         Traceback (most recent call last)
<ipython-input-9-a58ecfa5d5c9> in <module>
      4     user = api.users.get(user_ids = f, v = 5.103)[0]
      5     print(user['first_name'], user['last_name'])
----> 6     sleep(2)

KeyboardInterrupt: 

Теперь от сбора информации перейдем к ее генерации. Напишем небольшого бота, который будет отвечать на сообщения сообщества. Для этого нам потребуется другая библиотека, vk_api, ее можно установить, как обычно:

!pip install vk_api

Из этой библиотеки нам понадобятся функции из модуля longpoll, которые позволяют формировать «долгий» запрос к API ВКонтакте. С «долгими» запросами вместо того, чтобы обращаться к API каждую минуту в рамках написанного нами цикла, мы сможем написать код, который будет обращаться к API, ждать долгое время, пока мы не прервем исполнение кода, отслеживать происходящие события и реагировать на них. Другими словами, наш код будет очень гибким: если ничего не происходит, бот бездействует, если появляется что-то новое – сообщение, пост на стене или что-то еще – он мгновенно реагирует и пишет ответ.

In [10]:
import vk_api
from vk_api.longpoll import VkLongPoll, VkEventType

Чтобы написать бота, который будет отвечать на сообщения в сообществе, это сообщество сначала нужно создать. Заходим в раздел Сообщества на своей странице ВКонтакте, создаем новое сообщество. После создания заходим в Управление, далее – в раздел Сообщения. Заходим в подраздел Настройки для бота , включаем возможности бота. В разделе Сообщения также включаем сообщения сообщества, чтобы бот мог писать от его имени.

Затем переходим к подразделу Работа с API в разделе Настройки и создаем ключ. Этот ключ будет нашим токеном доступа, когда мы будет подключать бота из Python. Копируем ключ доступа и сохраняем его в переменную:

In [11]:
token = "7d..."

Открываем сессию работы с API и создаем объект longpoll для долгих запросов:

In [12]:
vk_session = vk_api.VkApi(token=token)
longpoll = VkLongPoll(vk_session)

Создаем объект vk, который будет обеспечивать нам действия ВКонтакте:

In [ ]:
vk = vk_session.get_api()

Теперь напишем специфический код.

Возьмем функцию longpoll.listen(), которая будет отслеживать события («прислушиваться»), и запустим цикл, который будет перебирать все новые события в сообществе (event) и, если это событие является новым текстовым сообщением (VkEventType.MESSAGE_NEW и event.text), проверять, что в этом сообщении написано, и отвечать на него.

In [14]:
for event in longpoll.listen():
    if event.type == VkEventType.MESSAGE_NEW and event.to_me and event.text:
        
        # если текст Привет! или привет
        # сообщаем погоду
        # делаем это, если сообщение от пользователя – from user
        if event.text == 'Привет!' or event.text == 'привет':
            if event.from_user:
                vk.messages.send(
                user_id=event.user_id,
                message='Привет! В Москве солнечно, ясно, -2',
                random_id=123456)
        # если текст пока 
        # пишем Пока!
        if event.text == 'пока':
            if event.from_user:
                vk.messages.send(
                user_id=event.user_id,
                message='Пока!',
                random_id=123457)

Конечно, данный пример учебный, но код выше можно всячески модифицировать, формулировать сложные условия, добавлять функции, которые будут действительно узнавать погоду на каком-нибудь сайте и отправлять ее пользователю и многое другое.

Важно: всегда указывайте в messages.send() аргумент random_id, без него метод работать не будет. Это случайный набор цифр, но он необходим. Про него можно почитать в документации API ВКонтакте в разделе, посвященном классу методов messages.

Примечание: код с longpoll выше заимствован отсюда.