GAE/Python で Twitter bot を作る(準備編)
先のエントリで bit.ly API モジュールやら Stack Stock Books API モジュールを作ったので、Google App Engine 上で動作する Twitter bot を作ってみます。
先のエントリとやらはこの辺です。
どんな処理にしましょうか?
ざっくりとこんな感じで。
- Stack Stock Books から最新のつぶやき取得
- Datastore に保存した前回のつぶやき情報と比較
- 新しい情報ならば、Twitter への投稿文言生成
- Twitter へ投稿
- Datastore に最新つぶやき情報を登録
- これらの処理を一定間隔で回す
ということで、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 に肝心のハンドラを書くだけです。
明日あたりに続くっ!