Twitter Streaming APIを試す

TwitterのStreaming API

TwitterStreaming APIを使ってみたくなりました。
Streaming APIというのは、まあその名前通りなのですが、ツイートがストリーミングされてくるAPIです。

大規模データで遊んでみたい

私は前職で音声認識用の統計的言語モデル(ことばの繋がりの関係を統計的に表したモデル)を生成するという業務も担当していました。

限定された範囲の音声認識ができれば良いのなら言語モデルは小さくて良いのですが、より汎用的で、より良い言語モデルを作るには(さらに言うならより良い音声認識をするには)、多くの例となる日本語文章を集める必要があります。この例文を集めたものをコーパスと呼びます。

前職ではツイートを集めてコーパスとし、言語モデルを生成したところ、わりと良い言語モデルを得ることができました。音声認識させる発話の内容にもよりますが、有名なコーパスである日本語話し言葉コーパス(CSJ)による言語モデルよりも音声認識性能が向上したように思います。
ちなみに、ツイートは文章としてはゴミが多いので(文章の内容が悪いというよりも顔文字のようなものが多い)、そのゴミをいかにうまく削除するかも問題でしたが、わりとザクザクと切り捨てても大丈夫でした。

そのときは同僚の方がStreaming APIを使ったスクリプトを組んでツイートを収集してくれましたが、自分でも大規模データで遊んでみたいと思い、スクリプトを組んでみることにしました。

コンピュータの何がいいかって、でかいデータをぶん回して、ハードディスクがうなりを上げ、LEDがピカピカ光るのがいいんですよね。一家に1台スパコンが欲しいところです。

Rubyで試してみる

私はスクリプト言語を扱ったことがほとんどなく、十年以上前にRuby(+PostgreSQL)で自分用のブックマーク管理Webアプリを書いた程度です。でも、その頃、オープンソースまつりというイベントのRubyワークショップで、まつもとさんにいただいたサインはちょっと自慢です。;)

今回も記憶の彼方に少しだけ残っている気がするRubyで書いてみることにしました。

仕様としては、「日本語のツイートを集めてファイルに落とす」というだけのものです。
Streaming APIにはいくつかのメソッドがあるのですが、目的からすれば「sample」というもので良さそうです。これは全ツイートのうちの1%くらいのツイートをランダムに選んで送ってくるというものです。

これを簡単に試してみるには、ブラウザで https://stream.twitter.com/1/statuses/sample.json にアクセスしてみれば良いだけです。
アクセスするとユーザ名とパスワードを尋ねられますが、Twitterアカウントを入力してください。すると、レスポンスはJSON形式でストリーミングされてきます。

じつを言うと、私のWeb系スキルは10年以上前にほぼ止まっているので(いまでもHTML 2.0〜3.0程度の知識でHTMLは手入力)、いままでJSONが何かも知りませんでした。

でも、ブラウザで得られたJSONでのレスポンスをエディタで開いて眺めてみると、JSONはkey:valueなカタチが基本だということがわかりました。また、このメソッドでどういったものが得られるのかもわかりました。

あとはこのメソッドを使ってスクリプトを組むだけ。
とは言え、そんなものはググったらすぐに出てきそう。
そこで、「twitter streaming api ruby」をググってみました。日本語のページがいくつもあらわれますが、どうも内容が古いようです。使われているメソッドが古く、現在のStreaming APIhttpsにしか対応していないのにhttpが使われていたりします。
説明文でも「BASIC認証のみ」とか書かれていたりするところもありますが、実際のところ、現在のStreaming APIではOAuthとBASIC認証の2通りが使えます。

tweetstream

調べていくと、Rubyにはtweetstreamというライブラリがあるようです。それとは別にtwitterstreamというものもあるようです。
どちらも導入するにはgemというものが必要とのこと。gemとはRubyのパッケージ管理システムらしい。十年以上前にはそんなものはなかった……ような気がする。
tweetstreamの導入にはgcc(g++)が必要だけれど、twitterstreamではいらない、と。
どちらでも良いのですが、なんとなくtweetstreamにしてみました。
gemでtweetstreamをインストール。

sudo gem install tweetstream

スクリプトを書いてみた

またググって「tweetstream ruby」の検索結果を見てみたのですが、どうも古いバージョンのtweetstreamを使っている説明しか見当たりません。しかたがなく、tweetstreamのドキュメントを見て(英語が苦手なのでこういう真っ当な手順が最後になるわけで)、ごく簡単なスクリプトですが自分で書いてみました。

認証はOAuthのほうが良いのでしょうが、BASIC認証のほうがラクではあります。Twitter社としてはOAuthを薦めています。

if文で日本語ユーザ(日本語ツイートではない)を指定するとともに、1000人以上のフォロワがいるユーザの、リプライでないツイートという条件を指定してみました。
出力はとりあえず標準出力です。

なお、yajl-rubyというライブラリが入っていないというエラーが出たので、これもgemを使って導入しました。

#!/usr/bin/ruby
#coding:utf-8

require 'rubygems'
require 'tweetstream' 

TWITTER_USERNAME='USERNAME'
TWITTER_PASSWORD='PASSWORD'

TweetStream.configure do |config|
  #BASIC認証版
  config.username = TWITTER_USERNAME
  config.password = TWITTER_PASSWORD
  config.auth_method = :basic
  config.parser   = :yajl #using Yajl-Ruby
end

TweetStream::Client.new.sample do |status|
  #日本語を使っていてフォロワーが1000人以上いるユーザで
  #リプライツイートでないツイートを表示
  if status.user.lang == 'ja' \
  && status.user.followers_count >= 1000 \
  && status.in_reply_to_user_id == nil 
    puts status.user.screen_name \
    + "(#{status.user.followers_count}): " \
    + status.text
  end 
end

試してみた

これをまた少しいじって日本語ユーザという条件だけにし、日付をファイル名としたログファイルに出力するようにしました。

出力内容は、

  • ツイートのポスト日時
  • リプライか否かフラグ
  • アカウント名
  • ツイート本文

としました。

ここまではMacでやってきたのですが、運用マシンとしては余っていたWindowsノート(P4/2.4GHz)を潰してUbuntuを入れました。最近のLinuxディストリビューションは導入にあたってとくに問題も発生せず、ラクで良いですね。

Macで使っていたRubyのバージョンは1.8.7でした。

% ruby -v
ruby 1.8.7 (2010-01-10 patchlevel 249) [universal-darwin11.0]

UbuntuにはRubyのバージョンをとくに意識することなく入れたのですが、1.9.2でした。

$ ruby -v
ruby 1.9.2p290 (2011-07-09 revision 32553) [i686-linux]

それでも問題なく動いたようです。じつはRubyのバージョンの違いに気付いたのは、結果が得られたあとでした。

昼の12時55分から動かし、いま(深夜3時に)見てみたところ、エラーで23時52分に終了していました。
まだ調べていませんが、長時間接続しっぱなしなのを防ぐためにサーバ側から切断してきたのかもしれません。もしそうなら、cronなどでプロセスの稼働を確かめてプロセスを再起動するなどしたほうが良さそうです。

得られたツイート達

稼働していた約11時間で、196,180ツイートを捕獲できました。1時間あたり約1万8千ツイート、1秒あたり約5ツイートというところです。これが本当に1%だとすると、日本各地で1秒あたり500人がツイートしていることになりますね。

参考までに、ファイルの最初と最後をheadとtailで表示してみたのが次のものです。なお、アカウント名はxxxxxxxxにしてあります。手作業で。;(

$ head 20111214
2011/12/14	12:55:49	P	xxxxxxxx	こんにちは♪皆さん、風邪に気をつけましょう!"@xxxxxxxx: @xxxxxxxx @xxxxxxxx @xxxxxxxx @xxxxxxxx @xxxxxxxx おはよー(^^)"
2011/12/14	12:55:49	P	xxxxxxxx	良い感じ!RT @xxxxxxxx: おっ!!RT @xxxxxxxx: http://t.co/51pNTQ5F デンプンの曲が入ってくるぞ。@xxxxxxxx
2011/12/14	12:55:49	R	xxxxxxxx	@xxxxxxxx 拗ねちゃいや!花嫁姿見せるから!
2011/12/14	12:55:50	P	xxxxxxxx	食後のジュースじゃんけんに初参戦したけど負ける気がしなかった。りこなんじゃないところでの勝負は心に余裕が持てる。
2011/12/14	12:55:50	P	xxxxxxxx	バス内で若妻を集団痴漢! http://t.co/NrXhzUBn #エロ動画 #アダルト #スマホ #携帯
2011/12/14	12:55:50	R	xxxxxxxx	@xxxxxxxx 何ぺ??
2011/12/14	12:55:50	P	xxxxxxxx	ちょっ!!(^◇^;)RT @xxxxxxxx: @xxxxxxxx いえ、ダブルクォーターパウンダーチーズ2つ重ねです。
2011/12/14	12:55:52	R	xxxxxxxx	@xxxxxxxx カッコいいからダメです(笑)
2011/12/14	12:55:53	R	xxxxxxxx	@xxxxxxxx メモリ差?
2011/12/14	12:55:53	P	xxxxxxxx	先生やたらめったら褒めてくれるから調子のりそう(笑)
$ tail 20111214
2011/12/14	23:52:41	R	xxxxxxxx	@xxxxxxxx 奇遇ね、明日ヒトカラ予定。
2011/12/14	23:52:42	P	xxxxxxxx	<・><・> RT @xxxxxxxx: ここもやばいころされる\(^o^)////////あとボレロの後ろ何ぴょんびょん可愛いよ  http://t.co/yN8rgYTz
2011/12/14	23:52:42	P	xxxxxxxx	RT @xxxxxxxx: 【拡散希望】関ジャニ∞ドームツアー《求》12月29日1枚お席問いません。仕事の都合で29日しか参戦できない友達が探しています。31日1部1枚との交換も可能です。お心当たりのある方はりぷかDMお願いします。
2011/12/14	23:52:42	R	xxxxxxxx	@xxxxxxxx ツイートの後半で毎回病んでる感じやめろよw
2011/12/14	23:52:42	R	xxxxxxxx	@xxxxxxxx おすしは嫌いです(`・ω・´)キリック ドンの力で試験日程ずらしてください。てゆか試験なくしてください…。 うーおーじゃあ桐玖さんとえいかわくうかわに逢うために静岡行こうかや…⊂( ⊂(´_ゝ`) 金………………
2011/12/14	23:52:42	R	xxxxxxxx	@xxxxxxxx @xxxxxxxx やりますか(*^^*)
2011/12/14	23:52:43	R	xxxxxxxx	@xxxxxxxx 帰ったらまだミタさんやっててビックリした。おかげで癒されたわ〜
2011/12/14	23:52:43	P	xxxxxxxx	なんでも妹と行動したり話したりするのが一番楽しいです右にでるものなど居ません
2011/12/14	23:52:43	R	xxxxxxxx	@xxxxxxxx 最終回だけでも見るんだ!
2011/12/14	23:52:43	P	xxxxxxxx	さすがに、きょうは、くたくただ。でも、まだ、やることがいっぱい。ふにゃ(。-_-。)

ここまでが準備

今後はこれをmecabあたりで形態素解析し、Jubatusか何かで機械学習が……できるといいな。基本的にバッチ処理しかしないのでHadoopでも良いのですが、せっかく初めて手を付けるのなら新鮮なもののほうが美味しそうです。;)