Herokuの無料枠でTwitter Stream APIを常時監視 => DBに保存するRubyコード


TwitterのStreaming APIを使うと、流れてくるツイートを常時監視できます。

監視する対象は特定のキーワードだったり、特定のユーザーだったり、特定のサイトを指定したりできます。ユーザーの場合はユーザーのツイートに対するリプライも取得できるので、使って見るとかなり夢が広がるAPIです。

今回はこのTwitter Stream APIをHerokuで無料で監視しつつ、DBに蓄積するPGを書いたのでその紹介をしていきます。


🚌 ソースコード

今回作成したソースコードはこちら。

詳細の説明は省きますが、基本的には環境変数に「TwitterのAPIのキー情報」と「DBへの接続情報」を書いて、後はAPIをEventMachineで監視 => ツイートが取得できたらDBに書き込むようになっています。

今回はこのソースをツイートscan.rbとします。

require 'rubygems'
require 'bundler'
require 'mysql2'
require 'json'
Bundler.require
require 'twitter/json_stream'
# TwitterのAPIキー情報を環境変数から取得
TWITTER_CONSUMER_KEY ||= ENV['TWITTER_CONSUMER_KEY']
TWITTER_CONSUMER_SECRET ||= ENV['TWITTER_CONSUMER_SECRET']
TWITTER_OAUTH_TOKEN ||= ENV['TWITTER_OAUTH_TOKEN']
TWITTER_OAUTH_TOKEN_SECRET ||= ENV['TWITTER_OAUTH_TOKEN_SECRET']
FOLLOWS ||= ENV['FOLLOWS']
# DBへの接続情報を環境変数から取得
DB_HOSTNAME ||= ENV['DB_HOSTNAME']
DB_USER_NAME ||= ENV['DB_USER_NAME']
DB_PASSWORD ||= ENV['DB_PASSWORD']
DB_NAME ||= ENV['DB_NAME']
EventMachine::run {
stream = Twitter::JSONStream.connect(
:path => "/1.1/statuses/filter.json?follow=#{FOLLOWS}",
:oauth => {
:consumer_key => TWITTER_CONSUMER_KEY,
:consumer_secret => TWITTER_CONSUMER_SECRET,
:access_key => TWITTER_OAUTH_TOKEN,
:access_secret => TWITTER_OAUTH_TOKEN_SECRET
},
:ssl => true
)
stream.each_item do |item|
$stdout.print "item: #{item}\n"
$stdout.flush
# MySQLへ接続(Postgresなどを使う場合は適宜変更)
client = Mysql2::Client.new(:host => DB_HOSTNAME, :username => DB_USER_NAME, :password => DB_PASSWORD || '', :database => DB_NAME)
# Tweetのjsonをパース
tw_json = JSON.parse(item)
# DBに格納するためにエンコーディング
user_id = client.escape(tw_json['user']['id_str'])
user_name = client.escape(tw_json['user']['name'])
user_screen_name = client.escape(tw_json['user']['screen_name'])
user_image = client.escape(tw_json['user']['profile_image_url'])
user_description = client.escape(tw_json['user']['description']) rescue nil
text = client.escape(tw_json['text'])
post_media_url = client.escape(tw_json['entities']['media'].first['media_url']) rescue nil
twitter_status_id = client.escape(tw_json['id_str'])
twitter_reply_status_id = client.escape(tw_json['in_reply_to_status_id_str']) rescue nil
twitter_reply_user_id = client.escape(tw_json['in_reply_to_user_id_str']) rescue nil
twitter_reply_user_screen_name = client.escape(tw_json['in_reply_to_screen_name']) rescue nil
# tweetsテーブルに書き込み
client.query("INSERT INTO tweets (user_id, user_name, user_screen_name, text, post_media_url, user_image, user_description, twitter_status_id, twitter_reply_status_id, twitter_reply_user_id, twitter_reply_user_screen_name, updated_at, created_at) VALUES ('#{user_id}', '#{user_name}', '#{user_screen_name}', '#{text}', '#{post_media_url}', '#{user_image}', '#{user_description}', '#{twitter_status_id}', '#{twitter_reply_status_id}', '#{twitter_reply_user_id}', '#{twitter_reply_user_screen_name}', '#{Time.now}', '#{Time.now}')")
# MySQLとの接続を解除
client.close
end
stream.on_error do |message|
$stdout.print "error: #{message}\n"
$stdout.flush
end
# 再接続は書いていないです。書いて教えてくださいw
stream.on_reconnect do |timeout, retries|
$stdout.print "reconnecting in: #{timeout} seconds\n"
$stdout.flush
end
stream.on_max_reconnects do |timeout, retries|
$stdout.print "Failed after #{retries} failed reconnects\n"
$stdout.flush
end
}

🐠 foremanをつかったプロセス管理

今回のソースはforemanを使っています。Gemfileに次のコードを追加してbundle installを実行。

# プロセス管理
gem 'foreman'

次にforeman用の設定ファイルProcfileを作成。

tweetscan: bundle exec ruby tweetscan.rb

これで設定は完了です。次のコードを実行するとプロセスがスタートして、Twitter Streamの監視を始めます。

ただし現時点では、Twitterのキー情報やDBへの接続情報が登録されていないので失敗します。

foreman start

🍮 Twitterのキー情報の取得と環境変数への登録

まずは次のサイトでTwitterアプリケーションを登録してください。

(Sign in => アプリケーションの登録)

Twitter Developers

登録したら環境変数にTwitterキーを登録します。まずはローカルへのキー情報の登録です。foremanで管理しているプロセスでは、.envファイルに環境変数にしたい情報を書き込むと勝手に読み込んでくれます。

TWITTER_CONSUMER_KEY=xxx
TWITTER_CONSUMER_SECRET=xxx
TWITTER_OAUTH_TOKEN=xxx
TWITTER_OAUTH_TOKEN_SECRET=xxx

こういった面倒な手順をふむ理由は、キー情報が第三者に使われると悪いことをされる可能性があるからです。(.envはgitignore☆)

同じ流れで、DBの情報やAPIの引数なども環境変数に登録してください。

🎃 Herokuへのデプロイ

では、Herokuにソースコードをデプロイ。

(このまえにソースはローカルでGitにコミットしておいてください)

heroku create heroku-twitterscan --stack cedar
git push heroku master

続いて、環境変数にTwitterのキー情報やDBへの接続情報、APIの引数などを登録。

heroku config:set TWITTER_CONSUMER_KEY=xxx
heroku config:set TWITTER_CONSUMER_SECRET=xxx
heroku config:set TWITTER_OAUTH_TOKEN=xxx
heroku config:set TWITTER_OAUTH_TOKEN_SECRET=xxx

ちなみに、HerokuのDBの作成手順などは拙著の次の記事などがオススメです。

Heroku/Posgresqlでよく使うコマンド一覧

Rails4でheroku Pushまでの最短手順 [haml/bootstrap 3.0/postgresql or MySQL]

ということでtwitterscan.rbのプロセスを起動!

heroku scale twitterscan=1

次のコマンドでプロセスが起動しているか、確認できます。

heroku ps

ツイート結果はログからも確認できます!

heroku logs --tail

ということでHerokuの無料枠でツイートをチェックして、DBに格納までする手順でした。
こちらはGitHubでもソースコードを公開しておきます。

morizyun/ツイートscan GitHub

エンジニア経験浅いので、是非いろいろとツッコミをいただければ幸いです。よろしくお願いします! 

🐰 参考リンク

voloko/twitter-stream

HerokuでStreaming APIを使うTwitter Botを作る | monoの開発ブログ

RubyでMySQLに繋ぐためのruby-mysqlとmysql2 - tagomorisのメモ置き場

Convert datetime to mysql format on Ruby on Rails - Stack Overflow

📚 おすすめの書籍