ha's notepad II

メモ書きです。

RubyでTwitterのUserStreamを使う

前回紹介したRuby Twitter Gemで、ターミナルにテキストでTLを表示するクライアントを作ろうとした。最初に作ったコードは以下のような感じ。

# encoding: utf-8
require 'rubygems'
require 'twitter'

client = Twitter::REST::Client.new do |config|
  config.consumer_key        = API_KEY
  config.consumer_secret     = API_SECRET
  config.access_token        = ACCESS_TOKEN
  config.access_token_secret = ACCESS_TOKEN_SECRET
end

mytl = client.home_timeline #TLを取得
hist = []
while 1

	update = mytl - hist #前回取得したTLとの差分
	num = update.length - 1
	
	num.downto(0) do |i|
		id = update[i][:id] # TweetのID。ふぁぼRT等に使用
		username = update[i][:user][:screen_name] # 発言者ID
		contents = update[i][:text] # 発言内容
		str = username + ":" + contents
		puts str

	end
	hist = mytl
	sleep(90)
	mytl = client.home_timeline
end

90秒ごとにclient.home_timelineでTLを取得し、前回取得しなかったぶんを「ID:発言内容」という形式で表示できる。client.home_timelineで取得したTLは新しいものから古いものへと順になった配列になっているため、downtoを使うことで古いものから順に表示させるようにしている。

ここで問題になったのが、APIの制限だ。このgem(以下twitter gem)ではTLを取得するたびにAPIを使用する必要があり、リアルタイムに更新しようとすると15分に15回までというTwitterAPIの制限に簡単に達してしまう。これを避けるために更新頻度を90秒間隔に落としているが、これでは応答が遅くなってしまう。また、client.home_timelineでは一度に20件しか取得できないようなので、フォロー数の多い場合はTLの取得漏れが起きることもある。

そこで、UserStreamを使える新たなgemを使う。こちらがそれ。
 
tweetstream/tweetstream · GitHub

これを使って、以下のようなコードでTLの表示をリアルタイムで行うことが出来る。

# 認証

TweetStream.configure do |config|
	config.consumer_key = API_KEY
	config.consumer_secret = API_SECRET
	config.oauth_token = ACCESS_TOKEN
	config.oauth_token_secret = ACCESS_TOKEN_SECRET
	config.auth_method = :oauth
end

# TL取得

streamclient = TweetStream::Client.new
streamclient.userstream do |status|

	username = status[:user][:screen_name]
	contents = status[:text]
	id = status[:id]
	str = username + ":" + contents
	puts str
	
	
end

認証部分はtwitter gemとよく似た方法でできる。gemのサイトに使用例がいくつかあるが、streamclient.userstreamの部分を色々変更してやれば、検索やリプに即座に反応するよなbotを作成することも容易だろう。
ただし、これはあくまでUserStreamを利用してツイートを取得するだけなので、botとしてつぶやいたりふぁぼったりといった動作をするにはtwitter gemを利用する必要がある。
以下にtweetstreamとtwitter gemを利用して、起動時に過去のツイート20件を取得し表示してからUserStreamによるリアルタイム更新を行い、特定のワードに反応してリプを飛ばすクライアント兼botのようなものの例を載せる。

# encoding: utf-8
require 'rubygems'
require 'twitter'
require 'tweetstream'
require 'reply_judge.rb' # 反応するかどうかを判定


TweetStream.configure do |config|
	config.consumer_key = API_KEY
	config.consumer_secret = API_SECRET
	config.oauth_token = ACCESS_TOKEN
	config.oauth_token_secret = ACCESS_TOKEN_SECRET
	config.auth_method = :oauth
end

normalclient = Twitter::REST::Client.new do |config|
  config.consumer_key        = API_KEY
  config.consumer_secret     = API_SECRET
  config.access_token        = ACCESS_TOKEN
  config.access_token_secret = ACCESS_TOKEN_SECRET
end


puts "Configuration Success"

# twitter gemで初回更新

mytl = client.home_timeline
19.downto(0) do |i|
	id = mytl[i][:id]
	username = mytl[i][:user][:screen_name]
	contents = mytl[i][:text]
		
	str = username + ":" + contents
	puts str

end

# tweetstream使用

streamclient = TweetStream::Client.new
streamclient.userstream do |status|
	username = status[:user][:screen_name]
	contents = status[:text]
	id = status[:id]
	str = username + ":" + contents
	puts str
	
	if reply_judge(username,contents) != 0

		time = Random.new.rand 10.0
		# time = 0.1
		sleep(time)
		str = "@" + username + " foobar"
		normalclient.update(str, :in_reply_to_status_id => id) # リプ先のID指定

	end
	
end