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

先のエントリで bit.ly API モジュールやら Stack Stock Books API モジュールを作ったので、Google App Engine 上で動作する Twitter bot を作ってみます。


先のエントリとやらはこの辺です。

どんな処理にしましょうか?

ざっくりとこんな感じで。

  1. Stack Stock Books から最新のつぶやき取得
  2. Datastore に保存した前回のつぶやき情報と比較
  3. 新しい情報ならば、Twitter への投稿文言生成
  4. Twitter へ投稿
  5. Datastore に最新つぶやき情報を登録
  6. これらの処理を一定間隔で回す


ということで、URL 的にはこんな感じに。

  • /:紹介文でも表示しましょう
  • /ssbbot/mumble/update/:cron がここを叩いて上記処理を走らせる

必要なモジュールのソースをダウンロード

以下のモジュールのソースを取得します。

そして、先のエントリで自作したモジュール。


これらのモジュールのソースコードを ssbbot ディレクトリ以下に配置します。

./ssbbot/
|-- bitly.py
|-- simplejson
|-- ssb.py
`-- twitter.py


ちなみにキモの python-twitter は 0.6 を使用していますが、Api クラスにおいてファイルキャッシュを使っているために、素のままでは GAE で使えません。今回は以下のような Monkey patch を twitter.Api を利用する前に書いて、その場しのぎを…

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

アプリケーション設定ファイルの作成

ssbbot ディレクトリに、アプリケーション設定ファイル app.yaml を以下のような内容で追加します。

application: YOUR_APP_ID
version: 1
runtime: python
api_version: 1

handlers:
- url: /ssbbot/.*
  script: main.py
  login: admin

- url: /.*
  script: main.py

今回は /ssbbot/以下の URL は cron (と管理者)だけが叩けるようにしたいので、login: admin で、管理者権限を持つユーザーのみがアクセスできるようにしています。

スケジュールタスク設定ファイルの作成

更新処理を cron で処理を走らせたいので、ssbbot ディレクトリにスケジュールタスク設定ファイル cron.yaml を以下のように追加します。

cron:
- description: update mumble job
  url: /ssbbot/mumble/update/
  schedule: every 30 mins

ここでの間隔は30分にしていますが、あまり間隔が空いてしまうと更新データの取りこぼしが出てしまいますし(今回のアプリでは最新の一件しか投稿しませんw)、かと言って短か過ぎると、利用 API や GAE の制限に引っかかったり迷惑をかけてしまうので程々にします。

models.py の作成

Twitter に投稿されたつぶやき情報を保持するため、MumbleModel という Datastore モデルを作成します。


ssb モジュールの Mumble クラスは多くのプロパティを持ちますが、今回は既に投稿済みかどうかを比較するためだけに使用するので、保持するプロパティは mumble_id と time、そしてデータストアに登録した日時だけにしています。

#!/usr/bin/env python
# -*- coding:utf-8 -*-
from google.appengine.ext import db

class MumbleModel(db.Model):
    """
    >>> mumble = Mumble()
    >>> mumble.mumble_id = 123
    >>> mumble.time = datetime(2009, 8, 3, 22, 34, 36)
    >>> mumble.put()
    >>> db.put(mumble)
    """
    key_format = "mumblemodel/%(mumble_id)s"
    
    mumble_id = db.IntegerProperty(required=True)
    time = db.DateTimeProperty(required=True)
    created = db.DateTimeProperty(auto_now_add=True)

main.py の作成

ハンドラに行く前に、メイン処理を書いちゃいます。

#!/usr/bin/env python
# -*- coding:utf-8 -*-
from google.appengine.ext import webapp
from google.appengine.ext.webapp.util import run_wsgi_app

from views import *

def main():
    app = webapp.WSGIApplication([
        (r'/', MainHandler),
        (r'/ssbbot/mumble/update/', BotHandler),
        ], debug=True)
    run_wsgi_app(app)

if __name__ == '__main__':
    main()


よし、これで残りは views.py に肝心のハンドラを書くだけです。


明日あたりに続くっ!