Как стать автором
Обновить
VK
Технологии, которые объединяют

ICQ New: инструкция по разведению ботов

Блог компании VK Мессенджеры *Python *


Каждый раз, заходя в мессенджер, мы встречаем ботов в самых различных своих проявлениях. Одни рассказывают про погоду, другие разыгрывают бургеры, а третьи так и вообще кидают мемы под настроение. Наверняка у многих из вас проскакивала мысль: «А не сделать ли мне своего бота?». К сожалению, частенько такие мысли разбиваются о непонимание, как вообще сделать бота. Наверное, для этого нужно быть крутым айтишником и разбираться в миллионах технологий? На самом деле, нет. И сегодня мы попытаемся показать, что создание своего бота — процесс простой и понятный. Разберем полный цикл создания бота, от получения необходимых данных из мессенджера до написания кода и его запуска на сервере.

Некоторое время назад в ICQ сильно обновилась платформа ботов. Она стала более дружелюбной, понятной и удобной. С помощью Python-библиотеки от разработчиков мы и будем создавать своего первого бота.

Первым делом


Для начала, нужно быть зарегистрированным в ICQ. Сделать это можно через приложение для мобильного телефона, компьютера или прямо из браузера в веб-версии.

После регистрации можно приступать к заведению собственного бота в системе:

  1. Найти metabot в ICQ.
  2. Написать ему команду /newbot.
  3. Отправить имя для своего нового бота (должно оканчиваться на bot).

После этого metabot пришлет данные вашего бота:

  • botId: уникальный номер бота;
  • nick: имя бота для поиска;
  • token: токен, который используется для сетевых запросов к серверу.

Всё, бот создан. Его можно найти в поиске, написать ему сообщение. Теперь нам нужно сделать так, чтобы бот был активным и что-то отвечал.

На страннице https://icq.com/botapi/#/ есть полное описание методов API. Они используются для взаимодействия с сервером. Разберем некоторые из них подробнее.

Базовый метод — /events/get. Он используется для получения новых событий бота. Например, если кто-то написал боту, то это событие будет отдаваться при запросе /events/get. Давайте напишем боту какое-нибудь сообщение и проверим появление соответствующего события. Сделать это можно, например, в браузере. Для этого нужно перейти по адресу https://api.icq.net/bot/v1/events/get?token=Ваш токен&pollTime=1&lastEventId=0. Параметр pollTime отвечает за длительность удержания запроса сервером. Например, если ввести значение 60, то сервер в течение 60 секунд будет ждать событий для бота, а если их не будет за это время, то сервер вернет пустой массив событий. lastEventId отвечает за последнее обработанное событие. Другими словами, события со значениями меньше, чем переданное, будут отсечены.

После перехода по этому адресу на экране появится что-то подобное:

{
 "events": [
  {
    "eventId": 41,
     "payload": {
         "chat": {
           "chatId": "745294945",
            "type": "private"
         },
         "from": {
                "firstName": "Andrey",
                "lastName": "Shvedov",
                "nick": "shvedoff",
                "userId": "745294945"
         },
         "msgId": "6831171945581511151",
         "text": "а",
         "timestamp": 1590506161
     },
     "type": "newMessage"
  }
 ],
 "ok": true
}

Таким же образом можно отправить сообщение от имени бота с помощью метода /messages/sendText.

Изучать эти методы подробнее не нужно, у нас есть готовая Python-библиотека, которая позволяет, не вдаваясь в подробности, писать своего бота.

Пишем код?


Да, но для начала нам нужно подготовить для этого свой компьютер. Будем использовать Python третьей версии (скачайте версию для своей ОС здесь: https://www.python.org/downloads/ и менеджер пакетов pip здесь: https://pip.pypa.io/en/stable/installing/ ) Также, нужно установить библиотеку для работы с ботами:

$ pip3 install --upgrade mailru-im-bot

Вот теперь можно приступать.

Пишем!


В качестве примера будем писать игрового бота, который будет проверять знания простейшей математики. Работать он будет так: человек пишет боту какое-нибудь сообщение, тот представляется и предлагает поиграть. После того, как пользователь соглашается, бот генерирует простой математический пример и 4 варианта на выбор. Когда пользователь нажимает кнопку с выбранным ответом, бот отвечает, правильно или неправильно.

Итак, бот в первую очередь должен получать события от сервера. Для этого нам нужно, помимо импортирования всех библиотек, создать объект класса Bot и запустить получение обновлений:

import logging
from bot.bot import Bot


logging.basicConfig(format='%(asctime)s %(levelname)s %(message)s',
                    datefmt='%Y.%m.%d %I:%M:%S %p', level=logging.DEBUG)

TOKEN = "" #your token here

def main():
    bot = Bot(token=TOKEN)
    bot.start_polling()


if __name__ == '__main__':
    main()

Здесь мы импортируем библиотеку для журналирования и запускаем ее. Также импортируем библиотеку для ICQ-ботов, задаем необходимый параметр token, создаем объект класса Bot и запускаем получение обновлений от сервера (bot.start_polling()).

Сейчас наш бот может получать события, но не может их обрабатывать. Дополним бота, чтобы он мог отвечать на сообщения. Для этого добавим необходимые импорты:

import json
from bot.handler import MessageHandler

json нужен для форматирования части сообщения, отвечающей за кнопки. MessageHandler нужен для добавления в код обработчика новых сообщений.

Далее, нам нужна функция, которая будет составлять сообщение для ответа:

def startup(bot, event):
    default_markup = [
        [{"text": "Начать!", "callbackData": "start"}]
        ]

    first_message_text = "Привет! Я - игровой бот. Начнем?"
    bot.send_text(chat_id=event.from_chat,
         text=first_message_text,
         inline_keyboard_markup=json.dumps(default_markup))

Она принимает на вход созданного бота и событие нового сообщения. default_markup — матрица кнопок (объект «список», состоящий из массива строк кнопок. В нашем случае это единственная кнопка Начать!). first_message_text— строка, текст которой будет отправлен пользователю. Метод send_text принимает:

  • chat_id (поле из обрабатываемого события) — идентификатор чата, из которого было получено сообщение,
  • текст отправляемого сообщения,
  • и inline_keyboard_markup — наши кнопки.

Теперь осталось описать вызов этой функции при получении сообщения. Для этого в библиотеке есть специальная конструкция:

bot.dispatcher.add_handler(MessageHandler(callback=startup))

Она позволяет при получении нового сообщения автоматически вызывать функцию startup() с необходимыми параметрами. Этот обработчик нужно поместить в функцию main(). У нас получился вот такой код, который позволяет отправлять стартовое сообщение при получении ботом любого сообщения:

import logging
import json
from bot.bot import Bot
from bot.handler import MessageHandler

logging.basicConfig(format='%(asctime)s %(levelname)s %(message)s',
                    datefmt='%Y.%m.%d %I:%M:%S %p', level=logging.DEBUG)

TOKEN = «» #your token here

def startup(bot, event):
    default_markup = [
        [{«text»: «Начать!», «callbackData»: «start»}]
        ]
    first_message_text = «Привет! Я — игровой бот. Начнем?»
    bot.send_text(chat_id=event.from_chat,
        text=first_message_text,
        inline_keyboard_markup=json.dumps(default_markup))

def main():
    bot = Bot(token=TOKEN)
    bot.dispatcher.add_handler(MessageHandler(callback=startup))
    bot.start_polling()

if __name__ == '__main__':
    main()

Для пользователя это будет выглядеть так:


Рассмотрим подробнее кнопку, которую мы отправляли в сообщении:

[ [{«text»: «Начать!», «callbackData»: «start»}]]

Помимо текста, который написан на кнопке, в сообщении есть поле callbackData. При нажатии на кнопку сервер генерирует событие нажатия на кнопку. В нём он передает это поле как идентификатор нажатой кнопки. То есть, по этой строке, полученной от сервера, мы можем судить, какую именно кнопку нажал пользователь. таким образом, дальше нам нужно добавить в бота логику обработки нажатия на кнопку. Для этого нам снова потребуется импортировать необходимые методы:

from bot.handler import BotButtonCommandHandler
from bot.filter import Filter

Первая строка — обработчик события нажатия на кнопку, вторая — фильтр, помогающий понять, какая именно кнопка нажата. Также нам нужно описать логику ответа на нажатия кнопки:

def start(bot, event):
    question = ''
    operands = ["+", "-", "*"]
    operations_count = randrange(3)+2
    for i in range(operations_count):
        question += str(randrange(9))
        question += choice(operands)
    question = question[:-1]
    answer = eval(question)
    buttons = [
        [{'text': str(answer), 'callbackData': "right"},
         {'text': str(answer+1), 'callbackData': "wrong"}],
        [{'text': str(answer-1), 'callbackData': "wrong"},
         {'text': str(answer+2), 'callbackData': "wrong"}]]
    shuffle(buttons[0])
    shuffle(buttons[1])
    shuffle(buttons)
    bot.answer_callback_query(
        query_id=event.data['queryId'],
        text='Новый вопрос')
    bot.send_text(chat_id=event.data['message']['chat']['chatId'],
        text=question,
        inline_keyboard_markup=json.dumps(buttons))

По аналогии с сообщениями, функция принимает на вход такие же аргументы. Затем генерируется пример и массив кнопок с ответами. Один из ответов будет правильным. По этому признаку у ответов будут разные callbackData. В конце нужно обязательно вызвать метод answer_callback_query с параметрами:

  • query_id — уникальный номер события нажатия на кнопку,
  • и text — текст, который будет показан во всплывающей подсказке при нажатии на кнопку.

С помощью вызова этого метода мы покажем пользователю, что бот принял нажатие на кнопку. Иначе на кнопке какое-то время будет отображаться индикатор загрузки. Еще с помощью метода send_text нужно отправить само сообщение с вопросом и кнопками ответов.

Давайте сразу добавим и функции для обработки правильных и неправильных ответов:

def right(bot, event):
    bot.send_text(chat_id=event.data['message']['chat']['chatId'],
        text='Правильно!')
    start(bot, event)


def wrong(bot, event):
    bot.send_text(chat_id=event.data['message']['chat']['chatId'],
        text='Неправильно:(')
    start(bot, event)

Эти функции будут вызываться при нажатии на правильный и неправильный ответы. И после сообщения с правильным ответом пользователь получит новый вопрос.

Всё, осталось только добавить обработчики нажатия на кнопки:

    bot.dispatcher.add_handler(BotButtonCommandHandler(
        callback=start, filters=Filter.callback_data(«start»)))
    bot.dispatcher.add_handler(BotButtonCommandHandler(
        callback=wrong, filters=Filter.callback_data(«wrong»)))
    bot.dispatcher.add_handler(BotButtonCommandHandler(
        callback=right, filters=Filter.callback_data(«right»)))

В каждом из этих трех обработчиков записан фильтр по callbackData (например, filters=Filter.callback_data(«start»)) и функция для вызова.

На этом программирование бота завершено. Итоговый код выглядит так:

import logging
import json
from bot.bot import Bot
from bot.handler import BotButtonCommandHandler
from bot.handler import MessageHandler
from bot.filter import Filter
from random import randrange, choice, random, shuffle

logging.basicConfig(format='%(asctime)s %(levelname)s %(message)s',
        datefmt='%Y.%m.%d %I:%M:%S %p', level=logging.DEBUG)

TOKEN = "" #your token here


def startup(bot, event):
    default_markup = [
        [{"text": "Начать!", "callbackData": "start"}]
        ]

    first_message_text = "Привет! Я - игровой бот. Начнем?"
    bot.send_text(chat_id=event.from_chat,
        text=first_message_text,
        inline_keyboard_markup=json.dumps(default_markup))


def start(bot, event):
    question = ''
    operands = ["+", "-", "*"]
    operations_count = randrange(3)+2
    for i in range(operations_count):
        question += str(randrange(9))
        question += choice(operands)
    question = question[:-1]
    answer = eval(question)
    buttons = [
        [{'text': str(answer), 'callbackData': "right"},
         {'text': str(answer+1), 'callbackData': "wrong"}],
        [{'text': str(answer-1), 'callbackData': "wrong"},
         {'text': str(answer+2), 'callbackData': "wrong"}]]
    shuffle(buttons[0])
    shuffle(buttons[1])
    shuffle(buttons)
    bot.answer_callback_query(
        query_id=event.data['queryId'],
        text='Новый вопрос')
    bot.send_text(chat_id=event.data['message']['chat']['chatId'],
        text=question,
        inline_keyboard_markup=json.dumps(buttons))


def right(bot, event):
    bot.send_text(chat_id=event.data['message']['chat']['chatId'],
        text='Правильно!')
    start(bot, event)


def wrong(bot, event):
    bot.send_text(chat_id=event.data['message']['chat']['chatId'],
        text='Неправильно:(')
    start(bot, event)


def main():
    bot = Bot(token=TOKEN)
    bot.dispatcher.add_handler(MessageHandler(callback=startup))
    bot.dispatcher.add_handler(BotButtonCommandHandler(
        callback=start, filters=Filter.callback_data("start")))
    bot.dispatcher.add_handler(BotButtonCommandHandler(
        callback=wrong, filters=Filter.callback_data("wrong")))
    bot.dispatcher.add_handler(BotButtonCommandHandler(
        callback=right, filters=Filter.callback_data("right")))
    bot.start_polling()


if __name__ == '__main__':
    main()

Замечу, что в нем присутствуют импорты, необходимые для работы функции генерирования вопроса. Вместо этой и других функций можно написать какую-то свою логику :)

Где и как запускать?


Бота удобнее всего запускать на удаленном сервере. Есть множество сервисов, которые предлагают виртуальные серверы с доступами, достаточными для установки программ. Некоторые сервисы предоставляют бесплатный тестовый период. Раз уж мы Mail.ru, то и разбирать будем на примере Mail.ru Cloud Solutions. Там простой процесс регистрации, быстрый доступ к своему серверу, а также бесплатный тестовый период без привязки банковской карты и прочих трудностей.

  1. Регистрируем аккаунт на https://mcs.mail.ru/.
  2. Создаем инстанс виртуальной машины. Все настройки оставляем без изменений, их достаточно.
  3. Сервис предложит скачать ключ доступа. Скачиваем.
  4. Теперь заходим на свою виртуальную машину: ssh -i ./xxx.pem user@ip

    где ./xxx.pem — путь до скачанного ключа.
  5. После этого нам нужно установить необходимые программы и пакеты:

    $ sudo curl https://raw.githubusercontent.com/dvershinin/apt-get-centos/master/apt-get.sh -o /usr/local/bin/apt-get
    $ chmod 0755 /usr/local/bin/apt-get
    $ sudo apt-get install python3
    $ curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py
    $ python3 get-pip.py
    $ pip3 install --upgrade mailru-im-bot

    Здесь мы установили Python и все необходимые библиотеки для работы нашего бота.
  6. Осталось скопировать бота на сервер и запустить его. Из папки со скриптом выполняем: scp -i ./xxx.pem ./path/to_bot.py user@ip:~

    • ./xxx.pem — путь до ключа;
    • ./path/to_bot.py — путь до файла с ботом;
    • user@ip:~ — логин, адрес и путь, куда копировать бота.

    После этого файл с ботом окажется в домашней директории на удаленном сервере.
  7. Заходим обратно на сервер и запускаем: python3 ~/file_name.py, где file_name.py — имя нашего файла с ботом.

Что дальше?


В результате у нас получился самостоятельно работающий бот, лежащий на нашем личном сервере. Если вы хотите дальше осваивать создание ботов для аськи, то подробнее изучите документацию по API ботов и усложните внутреннюю логику работы вашего бота. А еще в ICQ есть чат, в котором можно задавать вопросы по ботам: https://icq.im/botapi_faq.

Полезные ссылки


https://icq.com/botapi/#/ — ICQ bot API.

https://github.com/mail-ru-im/bot-python — Python-библиотека для ICQ-ботов.

https://icq.im/metabot — получить токен и отредактировать бота.

https://github.com/shvedoff/Icq_buttons — бот, выполняющий все возможные действия с кнопками.

https://icq.im/AoLE1J5Ecm5DIjZh1gg — чат для вопросов по ботам.
Теги:
Хабы:
Всего голосов 55: ↑41 и ↓14 +27
Просмотры 7.8K
Комментарии Комментарии 20

Информация

Дата основания
Местоположение
Россия
Сайт
vk.com
Численность
5 001–10 000 человек
Дата регистрации
Представитель
Миша Буданов