/dev/null не нужен: пишем бота на Python, который будет присылать свежие мемасики

бот

Сегодня мы создадим бота для Facebook Messenger, который будет присылать нам свежие мемы, мотивационные сообщения и шутки. В этой статье есть большая часть информации, которую нужно знать для создания своего бота.

Вот так будет выглядеть финальная версия нашего приложения:

бот

Технический стек

Нам понадобятся:

  • Flask — фреймворк для разработки бэкенда. Поскольку он легкий, это позволит нам сосредоточиться на логике, а не на структуре папок;
  • Heroku — хостинг для бесплатного размещения нашего кода;
  • Reddit — как источник данных, потому что новые сообщения там появляются каждую минуту.

Создание приложения Reddit

Мы будем использовать Facebook, Heroku и Reddit. Во-первых, убедитесь, что у вас есть учетная запись в каждом из этих сервисов. Затем нужно создать приложение Reddit:

бот

Нажмите кнопку «create an app…» и следуйте инструкциям на экране:

бот

Два нижних поля не будут использоваться, поэтому оставьте их пустыми. В поле с описанием приложения лучше написать что-то связанное с проектом. Когда приложение начнёт делать много запросов, представители Reddit могут проверить, для чего оно.

Теперь, когда ваше приложение создано, вам нужно сохранить client_id и client_secret в безопасном месте:

бот

Первая часть нашего проекта выполнена. Теперь нам нужно настроить базу для нашего приложения Heroku.

Создание приложения на Heroku

Перейдите на сайт Heroku и создайте новое приложение:

бот

На следующей странице дайте своему приложению уникальное имя. Нажмите «Heroku CLI» и загрузите последнюю версию интерфейса командной строки Heroku для вашей операционной системы. Следуйте инструкциям на экране и вернитесь, как только интерфейс будет загружен.

бот

Создание базового приложения Python

Приведенный ниже код взят с сайта Константиноса Цапраилиса.

Мы будем редактировать файл в соответствии с нашими потребностями. Бот Facebook будет работать следующим образом:

  1. Facebook отправляет запрос на наш сервер всякий раз, когда пользователь пишет сообщение на нашей странице Facebook.
  2. Мы отвечаем на запрос Facebook и сохраняем идентификатор пользователя и сообщение, которое было отправлено на нашу страницу.
  3. Мы отвечаем на сообщение пользователя через Graph API, используя сохранённый идентификатор пользователя и идентификатор сообщения.

Подробный разбор приведенного выше кода доступен на веб-сайте Константиноса Цапраилиса. В этом посте я сосредоточусь главным образом на интеграции Reddit и использовании базы данных Postgres на Heroku.

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

Выполните вышеприведенные команды в терминале и поместите вышеуказанный код Python в файл app.py. Потом поместите в Procfile следующее:

Теперь мы должны сообщить Heroku, какие библиотеки Python будет использовать наше приложение. Эти библиотеки должны быть перечислены в файле requirements.txt:

Выполните следующую команду в терминале. Вы получите такой результат:

Теперь мы создадим Git-репозиторий, который затем может быть помещен на серверы Heroku. Для его создания мы должны выполнить следующие шаги:

  1. Войти в Heroku.
  2. Создать новый репозиторий.
  3. Сохранить состояние проекта в репозиторий.
  4. Отправить его на Heroku.

Для этого введите следующие команды в терминал:

Сохраните адрес из строки «remote: …» — это адрес вашего Heroku-приложения. Он понадобится нам на следующем этапе.

Создание приложения Facebook

Для создания приложения нам нужна его страница на Facebook. Таково требование Facebook — у каждого приложения должна быть страница.

Теперь нам нужно зарегистрировать новое приложение. Перейдите на страницу создания приложения и следуйте инструкциям ниже:

бот бот бот бот бот бот бот

Затем перейдите в свой файл app.py и замените PAT в строке 9 на Page Access Token, который мы сохранили выше.

Cохраните все и отправьте код в Heroku.

Теперь, если вы перейдете на страницу Facebook и отправите сообщение на эту страницу, вы получите своё собственное сообщение в ответ. Это подтвердит, что мы всё сделали верно. Если сообщение не пришло, проверьте логи Heroku, которые дадут вам некоторое представление об ошибке. Вы можете получить доступ к логам следующим образом:

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

Получение данных с Reddit

Мы будем использовать данные из следующих источников:

Установим praw — Python-библиотеку сайта Reddit. Это легко сделать, введя следующую команду в терминале:

Теперь протестируем некоторые прелести Reddit в оболочке Python. В документации чётко показано, как получить доступ к Reddit и его сообществам. Сейчас самое подходящее время, чтобы использовать client_id и client_secret, которые мы создали в первой части статьи.

Не забудьте добавить в свой собственный client_id и client_secret вместо ****.

В приложении используется limit = None. Это позволит получать как можно больше сообщений. Изображения мы будем использовать только из GetMotivated и Memes, а текстовые сообщения только из Jokes и ShowerThoughts.

Теперь, когда мы знаем, как получить доступ к Reddit, используя библиотеку Python, мы можем продолжить и интегрировать его в app.py.

Добавим несколько дополнительных библиотек в наш файл requirements.txt, чтобы он выглядел примерно так:

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

Но нам нужен идентификатор для каждого изображения или текста, отправляемого пользователю, чтобы не отправлять одну и ту же запись дважды. Чтобы решить эту проблему, мы будем использовать PostgresSQL и идентификаторы постов Reddit (у каждого поста на Reddit есть уникальный id).

Мы будем использовать отношение «многие-ко-многим». Создадим две таблицы:

  • пользователи;
  • посты.

Сначала определим их в нашем коде, а затем уже разберёмся, как это будет работать:

Таким образом, в таблице будет два поля. Имя будет идентификатором, отправленным с запросом Facebook Messenger Webhook. Посты будут связаны с другой таблицей — «Посты». В таблице сообщений есть имя и URL-адрес. «Имя» будет заполнено идентификатором поста Reddit, а URL — адресом этого поста.

Итак, теперь наш окончательный код будет работать так:

  1. Мы запрашиваем список сообщений из определенного сообщества Reddit:
  2. Проверяем, был ли конкретный пост отправлен пользователю ранее.
  3. Если сообщение уже было отправлено, мы будем продолжать запрашивать посты от Reddit, пока не найдем новую запись.
  4. Если сообщение не было отправлено пользователю, мы отправляем сообщение и выходим из цикла.

Итоговый код app.py выглядит так:

Отправьте его в Heroku:

Осталось последнее. Нам нужно сказать Heroku, что мы будем использовать базу данных. Для этого введите в терминале следующую команду:

Так мы создадим базу данных, которой достаточно для нашего проекта. Теперь нам нужно инициализировать её правильными таблицами. Для этого мы сначала должны запустить оболочку Python на нашем сервере Heroku:

Затем в оболочке Python ввести следующие команды:

Наше приложение готово! Поздравляю!

Некоторые интересные особенности кода

Во-первых, в коде используется функция быстрых ответов интерфейса Facebook Messenger Bot API. Это позволяет нам отправлять некоторые предварительно отформатированные данные, которые пользователь может быстро выбрать. Они будут выглядеть примерно так:

бот

С каждым запросом на публикацию в API Facebook мы отправляем дополнительные данные:

Еще одна интересная особенность кода заключается в том, как мы определяем, является ли сообщение текстом, изображением или видеозаписью. В сообществе GetMotivated некоторые изображения не имеют расширения «.jpg» или «.png» в их URL, поэтому мы полагаемся на:

Вы могли заметить эту строку кода в файле app.py:

Она гарантирует, что если новые записи не будут найдены для конкретного пользователя (у каждого сообщества есть максимальное количество «горячих» сообщений), приложению будет, что отправить. В противном случае мы получим ошибку.

Следующая функция проверяет, существует ли пользователь с определенным именем или нет. Если он существует, она выбирает этого пользователя из базы данных и возвращает его. Если он не существует, она создает его, а затем возвращает вновь созданного пользователя:

Исходный код приложения также доступен на Github.

Перевод статьи «Making a Reddit + Facebook Messenger Bot»