【TwitterAPI+PHP】Phorehoseを使ってTwitter Streaming APIでリアルタイムに超膨大なツイートを取得する
こんにちは。今回はPHPのライブラリ「Phirehose」を使って文章解析用データcorpusを作成してみようって記事です。
特定ワードを設定するとリアルタイムにTwitter Streaming APIからデータが送られてきます。
嘗てはUser streamっていう種類もあったんですが提供終了しまいた。
取り敢えずサンプルコードを見て学べ!ってことで早速実装しましょう。
Phirehoseをダウンロード
今回は先述したとおりPhirehoseっていうPHPライブラリを使用します。TwitterAPIを操るライブラリはTwistOauthやAbraham/TwitterOauthが有名ですがストリーミングAPIには対応してないのでPhorehoseを使います。
Composerを使ってでもインストール出来ます。ですが今回は手っ取り早くGitからパクります。cloneしてください。
git clone https://github.com/fennb/phirehose
これで導入は終わりです。早速コードを書いていましょう。
因みにPhirehoseって言うなの由来はStreamingAPIの種類に大企業専門、とんでもない額がかかるらしいfirehoseっていう奴がありそれをもじったものらしいです。
コードを実装
以下が特定ワード(複数指定可)を含むツイートを付加情報を付けてCSVファイルにエクスポートするコードです。
<?php
// タイムアウトしないように…
set_time_limit(0);
// ライブラリを読み込む(適宜ディレクトリを変更してください)
require_once('lib/Phirehose.php');
require_once('lib/OauthPhirehose.php');
class FilterTrackConsumer extends OauthPhirehose
{
public function enqueueStatus($status)
{
// ここの関数内で受信時の処理を書いていきます
$data = json_decode($status, true);
if (is_array($data) && isset($data['user']['screen_name'])) {
$text = preg_replace('/[\n\r\t]/', '', $data['text']);
$timeline = $data["id_str"] . "," . $data['user']['screen_name'] . ',' . $data['created_at'] . ',' . urldecode($text) . ",\n";
echo $data["id_str"]; // 確認のためIDを出力しています
$timeline = mb_convert_encoding($timeline, 'SJIS-win', 'ASCII, JIS, UTF-8, SJIS');
file_put_contents("sample.csv", $timeline, FILE_APPEND);
}
}
}
// APIの情報を定義
define("TWITTER_CONSUMER_KEY", "*******************************");
define("TWITTER_CONSUMER_SECRET", "***************************************************");
define("OAUTH_TOKEN", "************************************************");
define("OAUTH_SECRET", "*********************************************");
// 実行
$sc = new FilterTrackConsumer(OAUTH_TOKEN, OAUTH_SECRET, Phirehose::METHOD_FILTER);
$sc->setTrack(array('keyword1', 'keyword2'));
$sc->setLang('ja'); // 日本語指定
$sc->consume();
とても手短で簡単に実装できますね。一応Gistにもあげときます~
コード解説
べつに解説することもないんですけど…
単純にFilterTrackConsumerクラスのenqueueStatus関数の中に受信してきたデータをどう処理するかを書いて行きます。
そしてAPIの認証情報を定義してキーワードやリージョン・位置情報を指定したあと$sc->consume();で取得開始。
Windowsの場合の注意
Windowsで操作したいならファイル書き込みの際必ずSJIS-winでエンコードしてください。
Excelとかメモ帳で開くとバグります。文字化けね。なかなか治らなくなるのでご注意を…
$timeline = mb_convert_encoding($timeline, 'SJIS-win', 'ASCII, JIS, UTF-8, SJIS');
まぁmb_convert_encoding()関数で一発ですが。第3関数を”auto”じゃまずいらしいので一応全部選択してみました。
注意事項
何故かStreamingAPIはエラーに厳しいです。
なのであまり失敗しないように…って言うわけにも行かないと思いますがもしHTTP Errorとか言われたらAPI KeyとAccess Token Secretを再生成したら治ります。
+α ブラウザから取得したい場合
ターミナルシェル上以外のブラウザとかで取得したいなら次のコードをさっきのなんとか関数に追記してください。
ob_flush(); flush();
これはサーバーとの通信中でも逐次画面上に表示するために書くやつです。StreamingAPIは常にTwitterと通信をしっぱなしで取得するため(XMLHttpRequestのxhr.ReadyState 3の通信中みたいな感じ。)こういう処理が必要です…
※ターミナル上で↑を付けたままやるとエラー返されます。
サンプルデータ
一昨日あったシャニマスの福岡公演のハッシュタグをキーワードにセットして約12万件のツイートがCSV形式で取得できました

浮動小数点がある型(float)で保存してしまったからツイートIDがミスっちゃってます…まぁ良いでしょう。
ダウンロードは↓から。リンク切れはお問い合わせフォームからお願いします。コメントでは対応しません。
受信されるJSONデータ型
APIから帰ってくるツイートデータのJSONを配列に変換したやつを掲載します。
一個一個紹介してられないのでまぁご自分で確認してください…
array(25) {
["created_at"]=>
string(30) ""
["id"]=>
float(0.000000000000E+17)
["id_str"]=>
string(18) ""
["text"]=>
string(78) ""
["source"]=>
string(82) ""
["truncated"]=>
bool(false)
["in_reply_to_status_id"]=>
NULL
["in_reply_to_status_id_str"]=>
NULL
["in_reply_to_user_id"]=>
NULL
["in_reply_to_user_id_str"]=>
NULL
["in_reply_to_screen_name"]=>
NULL
["user"]=>
array(38) {
["id"]=>
float(0000000000)
["id_str"]=>
string(10) ""
["name"]=>
string(13) ""
["screen_name"]=>
string(8) ""
["location"]=>
string(27) ""
["url"]=>
NULL
["description"]=>
string(135) ""
["protected"]=>
bool(false)
["verified"]=>
bool(false)
["followers_count"]=>
int()
["friends_count"]=>
int()
["listed_count"]=>
int()
["favourites_count"]=>
int()
["statuses_count"]=>
int()
["created_at"]=>
string(30) ""
["utc_offset"]=>
NULL
["time_zone"]=>
NULL
["geo_enabled"]=>
bool(true)
["lang"]=>
string(2) ""
["contributors_enabled"]=>
bool(false)
["is_translator"]=>
bool(false)
["profile_background_color"]=>
string(6) ""
["profile_background_image_url"]=>
string(48) ""
["profile_background_image_url_https"]=>
string(49) ""
["profile_background_tile"]=>
bool(false)
["profile_link_color"]=>
string(6) ""
["profile_sidebar_border_color"]=>
string(6) ""
["profile_sidebar_fill_color"]=>
string(6) ""
["profile_text_color"]=>
string(6) ""
["profile_use_background_image"]=>
bool(true)
["profile_image_url"]=>
string(74) ""
["profile_image_url_https"]=>
string(75) ""
["profile_banner_url"]=>
string(59) ""
["default_profile"]=>
bool(true)
["default_profile_image"]=>
bool(false)
["following"]=>
NULL
["follow_request_sent"]=>
NULL
["notifications"]=>
NULL
}
["geo"]=>
NULL
["coordinates"]=>
NULL
["place"]=>
array(9) {
["id"]=>
string(16) ""
["url"]=>
string(56) ""
["place_type"]=>
string(4) ""
["name"]=>
string(16) ""
["full_name"]=>
string(23) ""
["country_code"]=>
string(2) ""
["country"]=>
string(6) ""
["bounding_box"]=>
array(2) {
["type"]=>
string(7) ""
["coordinates"]=>
array(1) {
[0]=>
array(4) {
[0]=>
array(2) {
[0]=>
float()
[1]=>
float()
}
[1]=>
array(2) {
[0]=>
float()
[1]=>
float()
}
[2]=>
array(2) {
[0]=>
float()
[1]=>
float()
}
[3]=>
array(2) {
[0]=>
float()
[1]=>
float()
}
}
}
}
["attributes"]=>
array(0) {
}
}
["contributors"]=>
NULL
["is_quote_status"]=>
bool(false)
["retweet_count"]=>
int(0)
["favorite_count"]=>
int(0)
["entities"]=>
array(4) {
["hashtags"]=>
array(0) {
}
["urls"]=>
array(0) {
}
["user_mentions"]=>
array(0) {
}
["symbols"]=>
array(0) {
}
}
["favorited"]=>
bool(false)
["retweeted"]=>
bool(false)
["filter_level"]=>
string(3) ""
["lang"]=>
string(2) ""
["timestamp_ms"]=>
string(13) ""
}