Twitterのuser_timelineから新着発言を取得して別サーバにPOST
Twitterに投稿した自分の新着発言を取得して、何らかの処理を行うことを考えます。
「はてなブックマークWeb Hook」のように、発言が投稿された時点でTwitter側からこちらの指定したURLを呼び出してくれれば都合が良いですが、そんなものはないので、cronで定期的にポーリングすることを試みました。
取ってきた発言に対する処理本体は別サーバ (特にHerokuなどのRubyホスティングサービス) で実行することを想定して、別のHTTPサーバにJSON形式でPOSTするという仕様にします。
(cronでRubyスクリプトを動かせるサーバがあるなら、それを使えばいいじゃないかという話もありますが…)
ひとまず動くものができたので公開します。
テスト環境
- Mac OS X 10.6 (Snow Leopard)
- Ruby 1.8.7-p248
- rubytter 1.2.2
- json 1.2.4
ソースコード
user_timeline_hook.rb:
require 'rubygems' require 'rubytter' require 'dbm' require 'json' require 'net/http' Net::HTTP.version_1_2 DB_FILENAME = "/var/local/timeline_status" # 状態記録用DBMファイル名 TL_COUNT = 10 # 一度に取得する最大発言数 SERVER_HOST = "localhost" # ポスト先サーバのホスト名 SERVER_PORT = 8080 # ポスト先サーバのポート番号 SERVER_PATH = "/post" # ポスト先サーバのパス # コマンドライン引数からTwitterユーザ名を取得 if ARGV.size < 1 abort("Usage: user_timeline_hook <user>") end user = ARGV[0] # 状態記録用DBから、前回取得した最後の発言のステータスID取得 since_id = 0 DBM.open(DB_FILENAME) {|db| if db[user] != nil since_id = db[user].to_i end } # Twitter APIを呼び出してユーザタイムライン取得 max_status_id = since_id client = Rubytter.new statuses = [] opts = {:count => TL_COUNT} opts[:since_id] = since_id if since_id > 0 statuses = [] client.user_timeline(USER_NAME, opts).each {|status| statuses << status if status.id > max_status_id max_status_id = status.id end } # 取得した最新のステータスIDを状態記録用DBに保存 DBM.open(DB_FILENAME) {|db| db[user] = max_status_id.to_s } # 取得した発言をJSON形式でPOST Net::HTTP.start(SERVER_HOST, SERVER_PORT) {|http| header = { 'Content-Type' => 'text/javascript+json; charset=utf-8' } body = statuses.to_json + "\r\n" response = http.post(SERVER_PATH, body, header) }
実行:
ruby -Ku user_timeline_hook.rb <Twitterユーザ名>
のような形で実行します。
メモ
おまけ: DBMファイル初期化
以下のスクリプトにより、DBMファイルを初期化します。実行するユーザによってはPermission Deniedになるので、DBMファイル (*.db) 自体は事前にtouchなどで作成しておく必要があります。
require 'dbm' DB_FILENAME = "/var/local/timeline_status" DBM.open(DB_FILENAME, 0644, DBM::NEWDB) {|db| }
実行:
$ ruby create.db
おまけ: テスト用クライアント
user_timeline_hook.rbが期待通り動作することを確かめるため、以下のスクリプトをポスト先サーバとして起動します。ここではWEBrickを使っています。
test-server.rb:
#!/usr/local/bin/ruby -Ku # -*- coding: utf-8 -*- require 'rubygems' require 'webrick' require 'pp' require 'json' class RequestHandler < WEBrick::HTTPServlet::AbstractServlet def do_POST(req, res) puts "Request header:" pp req.header puts "Request body:" d = JSON.parse(req.body) pp d res.content_type = "text/plain" res.status = WEBrick::HTTPStatus::RC_OK res.body = "Succeeded\r\n" end end srv = WEBrick::HTTPServer.new({:DocumentRoot => '/', :BindAddress => '127.0.0.1', :Port => 8080}) srv.mount('/post', RequestHandler) Signal.trap(:INT) { srv.shutdown } srv.start
実行:
$ ruby -Ku test-server.rb
このスクリプトを実行した状態で、user_timeline_hook.rb を実行することで、期待通りHTTPサーバへのPOSTが行われていることが確認できます。