GAE/Python で Twitter bot を作る(後編)

準備編 の続きは明日書くとか言っときながら、間が空いてしまいましたが後編を。

残るは肝心のハンドラ部分を実装していきます。

views.py の作成

main.py で指定したように、

  • /:TOP画面。ハンドラは MainHandler
  • /ssbbot/mumble/update/:cron がここを叩いて更新処理を走らせる。ハンドラは BotHandler

という感じで views.py を実装して行きましょう。

#!/usr/bin/env python
# -*- coding:utf-8 -*-
import logging

from google.appengine.ext import webapp

import twitter
import ssb
import bitly

from models import MumbleModel

def my_twitter_api_init(self,
                        username=None,
                        password=None,
                        input_encoding=None,
                        request_headers=None):
    """Monkey patche for twitter.Api.__init__ method.
    Just change _cache do not use FS cache.
    """
    import urllib2
    from twitter import Api
    self._cache = None
    
    self._urllib = urllib2
    self._cache_timeout = Api.DEFAULT_CACHE_TIMEOUT
    self._InitializeRequestHeaders(request_headers)
    self._InitializeUserAgent()
    self._InitializeDefaultParameters()
    self._input_encoding = input_encoding
    self.SetCredentials(username, password)
twitter.Api.__init__ = my_twitter_api_init


class MainHandler(webapp.RequestHandler):
    def get(self):
        """
        """
        self.response.out.write("Stack Stock Books つぶやき Bot")

class BotHandler(webapp.RequestHandler):
    """Bot 更新用ハンドラ"""
    def get(self):
        """
        """
        # 最新の SSB つぶやき取得
        ssbapi = ssb.Api()
        mumble = ssbapi.get_mumbles(include_books=False)[0]
        logging.debug("mumble: %s", mumble)

        key_name = MumbleModel.key_format % dict(mumble_id=mumble.mumble_id)
        mm = MumbleModel.get_by_key_name(key_name)

        if mm is not None and mm.time >= mumble.time:
            # 更新情報なし
            logging.info("No update: mumble_id: %s", mumble.mumble_id)
            self.response.out.write("No update")
            return

        # 書籍情報取得
        book = ssbapi.get_book(mumble.book_id)
        mumble.book = book
        
        # 投稿文言生成
        twitterapi = twitter.Api(username="TWITTER_USER", password="TWITTER_PWD")
        user = ssbapi.get_user(mumble.user_id)
        status = self._mumble_string(user, mumble)
        if len(status) > 140:
            status = status[:139] + u'\u2026'

        # Twitter 更新
        result = twitterapi.PostUpdate(status)
        logging.info("status: %s\nresult: %s", status, result)

        # 更新情報を登録
        mm = MumbleModel(key_name=key_name,
                         mumble_id=mumble.mumble_id,
                         time=mumble.time)
        mm.put()
        self.response.out.write("OK")

    def _mumble_string(self, user, mumble):
        url = mumble.uri
        api = bitly.Api()
        api.set_account("BITLY_LOGIN", "BITLY_APIKEY")
        try:
            url = api.shorten(url)
        except bitly.BitlyResponseError:
            pass
        
        return u"%(url)s %(nick)s『%(title)s』%(body)s" \
               % dict(nick=user.nick,
                      title=mumble.book.title,
                      body=mumble.body,
                      url=url)

BotHandler では、

  1. Stack Stock Books から最新のつぶやき取得
  2. Datastore に保存した前回のつぶやき情報と比較。更新が無ければ終了。
  3. 新しい情報ならば、Twitter への投稿文言生成。URL は bit.ly API を利用して短縮。
  4. 文言が140文字を越えていたら、139文字+'…' として切り詰め処理。
  5. Twitter へ投稿
  6. Datastore に最新つぶやき情報を登録

という処理をしています。

完成!

さて、これで簡単な Twitter bot ができました。ファイル構成は以下のようになっていると思います。

./ssbbot/
|-- app.yaml
|-- bitly.py
|-- cron.yaml
|-- main.py
|-- models.py
|-- simplejson
|-- ssb.py
|-- twitter.py
`-- views.py


あとはこれを GAE にデプロイすれば完成です。