- PVSM.RU - https://www.pvsm.ru -

Пишем бота для Twitter на основе GitHub API

Доброго времени суток, уважаемое читатели.

Сегодня пятница, а это значит, что можно отвлечься от серьезных проектов и отдохнуть. Например, прочитав очередную статью для начинающих, посвященную разработке простого twitter-бота на python, уведомляющего о нескольких видах GitHub-активности.

Если вы подозреваете, что ничего нового из этой статьи не узнаете, то можете просто посмотреть код проекта на GitHub [1]. Остальных же приглашаю под кат, чтобы узнать больше про библиотеки для взаимодействия с GitHub API v3 и ознакомиться с процессом написания бота.

Пишем бота для Twitter на основе GitHub API


Замечу, что на Хабрахабре легко найти руководства по написанию ботов для Twitter ([1] [2], [2] [3], [3] [4], ...) и сложно — по API для GitHub. Это, пожалуй, основная причина появления этой заметки. Кроме того, перед вами всего лишь простой пример использования огромных возможностей, которые нам доступны.

GitHub API

В настоящий момент актуальная версия API — третья (поддержка первых двух была отменена [5] в июне этого года). Для работы с ней посредством python существует как минимум [6] шесть библиотек, которые очень похожи. Я выбирал библиотеку, основываясь на наличии удобной документации и отсутствии большого количества зависимостей. Наиболее приятной показалась github3.py [7].

Twitter API

От Twitter'a требовалось очень немного — нужно было уметь авторизовываться, получать новые упоминания (mentions) и отправлять сообщения. Токен можно было получить вручную (он выдается один раз и не нуждается в обновлении). Поэтому я остановился на библиотеке oauth [8], портированной под третий python.

Разработка бота

Предполагалось, что бот будет работать следующим образом:

  • каждые N секунд обновлять сообщения, в которых его упомянули
  • находить среди них новые
  • формировать из сообщений команды
  • выполнять команды
  • сообщать о результатах выполнения пользователям

Структура проекта выглядит следующим образом:
Пишем бота для Twitter на основе GitHub API

Папка oauth содержит библиотеку для авторизации, в файле twitter.py методы для оправки сообщений и обновления ленты, github.py, по сути, является самим ботом, а в id.dat будет храниться номер последнего обработанного сообщения (на случай каких-то сбоев в работе). Config.py понадобится для хранения ключей и паролей.

Для работы с Twitter API нужно создать свое приложение. Авторизуемся на dev.twitter.com, нажмем «Create an app», заполним форму и создадим приложением. Чтобы отправлять сообщения, нужно включить режим «Read and write» в разделе «Settings». Осталось получить ключи («Create my access token» на вкладке «Details») и можно приступать.

twitter.py

Ссылки на полный код будут в конце статьи, здесь только краткие выдержки.

Сначала научим нашего бота авторизовываться в Twitter, отсылать запросы и сохранять номер последнего сообщения.

HOME_TIMELINE_URL = 'http://api.twitter.com/1/statuses/home_timeline.json'
UPDATE_URL = 'http://api.twitter.com/1/statuses/update.json'
MENTIONS_URL = 'http://api.twitter.com/1/statuses/mentions.json'
FILENAME = 'id.dat'  # File with the number of the last solved problem

Для обновления ленты достаточно установить соединение:

def _get_connection(self):
    self.connection = http.client.HTTPConnection('twitter.com')

И отправить POST-запрос:

oauth_request = oauth.OAuthRequest.from_consumer_and_token(
            self.consumer, token=self.access_token, http_method='POST',
            http_url=UPDATE_URL, parameters=params)
oauth_request.sign_request(self.signature_method, self.consumer,
            self.access_token)
self.connection.request(oauth_request.http_method, UPDATE_URL,
            headers=oauth_request.to_header(),
            body=self._to_query_string(params))

А для получения упоминания — GET-запрос:

oauth_request =
            oauth.OAuthRequest.from_consumer_and_token(self.consumer,
                            token=self.access_token, http_method='GET',
                            http_url=MENTIONS_URL, parameters=params)
oauth_request.sign_request(self.signature_method,
                                        self.consumer, self.access_token)
self.connection.request(oauth_request.http_method,
                    MENTIONS_URL + '?' + self._to_query_string(params),
                    headers=oauth_request.to_header())

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

def _save(self, data):
    path = os.path.dirname(__file__)
    path = os.path.join(path, FILENAME)
    log_file = open(path, 'wb')
    pickle.dump(data, log_file)
    log_file.close()

В принципе, для нашей задачи этого будет достаточно. Теперь создадим файл config.py, в котором будем хранить полученные нами ключи для Twitter API и логин/пароль пользователя GitHub (на случай, если нашему боту это понадобится):

import twitter
secret = twitter.SecretKeys('consumer_key',
            'consumer_secret',
            'auth_key',
            'auth_secret')
LOGIN = 'github_login'
PASSWORD = 'github_password'

И допишем оболочку для их хранения:

class SecretKeys:
    keys = {}

    def __init__(self, consumer_key, consumer_secret, auth_key, auth_secret):
        self.keys = {'consumer_key': consumer_key,
                     'consumer_secret': consumer_secret,
                     'auth_key': auth_key,
                     'auth_secret': auth_secret}
github.py

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

from github3 import login
import twitter  # twitter.py
import time
import os
import pickle
from config import secret, LOGIN, PASSWORD

Номер последнего сообщения будем брать из файла:

def get_data(filename):
    with open(filename, 'rb') as file:
        return pickle.load(file)

Список новых задач получим от twitter.py:

list_of_problems = api.get_new_mentions(idx)

И будем идти по нему, формируя новые команды:

for problem in list_of_problems:
        problem = form_problem(problem)

Функция form_problem() будет искать, что именно хотел от бота пользователь и формировать словарь с параметрами:

if command in commands:
        command = commands.index(command)
        user = problem['user']['screen_name']
        return {'command': command, 'user': user, 'params': params}

Затем нужно будет выполнить каждую из задач:

def solve(problem, gh):
    functions = {0: get_last_commit,
                 1: get_list_of_contributors,
                 2: get_count_of_open_issues,
                 3: get_count_of_commits,
                 4: get_count_of_repos,
                 5: subscribe_on_commits,
                 6: help,
                 7: unsubscribe_from_commits}
    return functions[problem['command']](gh, problem['params'],
                                         problem['user'])

Отправить пользователю результаты:

api.post_update('@%s %s.' % (problem['user'], result))

И сделать небольшую паузу:

time.sleep(10)

В принципе, этого достаточно для первой версии. Сами функции полностью основаны на GitHub API и документации к github3.py. Например, вывод последнего коммита в каком-либо репозитории можно реализовать так:

def get_last_commit(gh, params, user):
    pattern = 'Last commit in "%s" was "%s" by %s'
    repository = gh.repository(params[0], params[1])
    last_commit = repository.list_commits()[0]
    return pattern % (repository.name, last_commit.commit.message,
                    last_commit.commit.author.name)

С точки зрения GitHub API [9], это GET-запрос (/repos/:user/:repo/commits), в ответ на который сервер вернет список всех коммитов в репозитории с довольно обширной информацией:
Пишем бота для Twitter на основе GitHub API

Пожалуй, это все. Для запуска бот нужно просто запустить файл github.py, предварительно заполнив config.py. В настоящий момент GitToTweet поддерживает следующие команды:

  • Вывести последний коммит в репозитории: get last commit, <user>, <repository>
  • Вывести список участников: get list of contributors, <user>, <repository>
  • Вывести список открытых проблем: get count of open issues, <user>, <repository>
  • Вывести список коммитов в репозитории: get count of commits, <user>, <repository>
  • Вывести количество публичных репозиториев пользователя: get count of repos, <user>, <repository>
  • Подписаться на новые коммиты в репозитории: subscribe me, <user>, <repository>
  • Отписаться от новых коммитов в репозитории: unsubscribe me, <user>, <repository>
  • Вывести пример использования с ссылкой на github: help

А выглядит это примерно так:

@GitToTweet get last commit, django, django

@%username% The last commit in «django» was «Fixed #18847 — Updated for media examples to use static.example.com. Thanks Jamie Curle…

Ссылки

Исходный код проекта на GitHub:
github.com/valzevul/GitToTweet [1]

Документация по GitHub API v3:
developer.github.com/ [10]

Документация по Twitter API:
dev.twitter.com/docs [11]

Пример работы бота в Twitter можно посмотреть здесь:
twitter.com/GitToTweet [12]

Спасибо за внимание.

Автор: valzevul


Сайт-источник PVSM.RU: https://www.pvsm.ru

Путь до страницы источника: https://www.pvsm.ru/python/13724

Ссылки в тексте:

[1] код проекта на GitHub: http://github.com/valzevul/GitToTweet

[2] [1]: http://habrahabr.ru/post/127237/

[3] [2]: http://habrahabr.ru/post/128422/

[4] [3]: http://habrahabr.ru/post/139900/

[5] была отменена: http://developer.github.com/#changes

[6] как минимум: http://developer.github.com/v3/libraries/

[7] github3.py: http://github3py.readthedocs.org/en/latest/index.html

[8] oauth: http://code.google.com/p/oauth/

[9] GitHub API: http://developer.github.com/v3/repos/commits/

[10] developer.github.com/: http://developer.github.com/

[11] dev.twitter.com/docs: http://dev.twitter.com/docs

[12] twitter.com/GitToTweet: http://twitter.com/GitToTweet