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

  • Tutorial
Доброго времени суток, уважаемое Хабрасообщество.

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

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




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

GitHub API

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

Twitter API

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

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

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

Структура проекта выглядит следующим образом:


Папка 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, это GET-запрос (/repos/:user/:repo/commits), в ответ на который сервер вернет список всех коммитов в репозитории с довольно обширной информацией:


Пожалуй, это все. Для запуска бот нужно просто запустить файл github.py, предварительно заполнив config.py. В настоящий момент GitToTweet поддерживает следующие команды:
  • Вывести последний коммит в репозитории: get last commit, ,
    Вывести список участников: get list of contributors, ,
    Вывести список открытых проблем: get count of open issues, ,
    Вывести список коммитов в репозитории: get count of commits, ,
    Вывести количество публичных репозиториев пользователя: get count of repos, ,
    Подписаться на новые коммиты в репозитории: subscribe me, ,
    Отписаться от новых коммитов в репозитории: unsubscribe me, ,
    Вывести пример использования с ссылкой на 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

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

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

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

    Спасибо за внимание.
Метки:
Поделиться публикацией
Похожие публикации
Реклама помогает поддерживать и развивать наши сервисы

Подробнее
Реклама
Комментарии 13
  • НЛО прилетело и опубликовало эту надпись здесь
    • НЛО прилетело и опубликовало эту надпись здесь
      • +4
        Расскажите это разработчикам Ruby on Rails, jQuery или Django, например.
        • НЛО прилетело и опубликовало эту надпись здесь
          • +1
            Теперь любое долдонство, простите, называют троллингом.
      • 0
        1. Хранить логин/пароль гитхаба в исходниках не кошерно, тем более юзается oauth. К тому же вы сами сказали, что акксесс токен не нужно обновлять
        2. У API гитхаба нормальная документация, местами, конечно, не хватает побольше инфы о обязательных и опциональных параметрах, но это не страшно.
        3. У API гитхаба есть косяк — через него можно сделать репозиторий, но нельзя залить в него коммит, если этот реп пустой (initial commit нужен).
        4. Для работы с Twitter API советую библиотеку github.com/ryanmcgrath/twython — она единственная на сколько мне известно поддерживает твиттинг с картинками
        • 0
          1. Oauth для twitter'a, а библиотеке github3.py, как я понимаю, нужен логин и пароль для работы.
          2-3. Документация хорошая, согласен. Но плюс сторонних библиотек как раз в обработке подобных косяков — для начинающего куда комфортнее.
          4. Спасибо! Присмотрюсь. Просто в данном случае мне была нужна только oauth-авторизация, многофункциональная библиотека была бы излишней.
          • +1
            1. Значит надо выбрать другую библиотеку, которая использует их OAuth2 или просто посмотреть исходники и понять что можно и через access_token авторизоваться, только его ручками надо будет получать для этой библиотеки.
            • 0
              Понятно, спасибо, перепишу на авторизацию через token.
        • +1
          Ух ты ш ка.
          прикрутить такое к мониторингу, например…
          • 0
            Rainbow!
            • +2
              А что? Благодаря этому проект стал на 20% круче.
            • +1
              боты вконтакте, боты в твиттере, боты в одноклассниках. Ботов уже больше, чем живых людей.

              Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.