概要
やりたいこと
Twitter Streaming APIのstatuses/filterを使って、特定のハッシュタグを含み、かつ画像付きのつぶやきを取得してウェブサイトに表示させたい。
環境
- PHP 5.6.16
- FuelPHP 1.7
事前準備
Twitterのアプリケーション登録
まずは、Twitter側でAPIを使えるようにしないと・・・。
-
ということで、以下のURLにアクセス
-
「Create New App」をクリックして、必要事項を入力していきます。
- Name:アプリケーション名
- Description:アプリケーションの説明
- Website:アプリケーションのウェブサイト
- Callback URL:コールバック用のURL
最後に、英語の規約を頑張って読んで、「Yes, I agree」にチェックして、「Create Your Twitter application」をクリック。
-
アプリケーションが登録されたら、「Key and Access Tokens」タブをクリック。「Consumer Key」と「Consumer Secret」を入手できます。
「Consumer Secret」はほかの人に知られないよう、厳重に管理しましょう。
-
続いて、アクセストークンを取得します。同じ画面の下の方にある「Your Access Token」のなかに「Create my access token」というボタンがあるので、クリックしましょう。
さっきまで何もなかった「Your Access Token」のなかに、「Access Token」と「Access Token Secret」が出現します。
ライブラリ「Phirehose」の用意
調べてみたなかで、比較的メジャーと思しき「Phirehose」というライブラリを使わせていただきます。
-
Phirehoseをダウンロード
https://github.com/fennb/phirehose
ダウンロードしたら、解凍して
phirehose
とかにリネームしたうえで、/fuel/app/vendor
に放り込みましょう。 -
今回、
statuses/filter
を使うので、example
フォルダの中にある、filter-oauth.php
を、あらかじめphirehose直下に移動しておきます。
実装
今回、常時実行プロセスで、つぶやきをひたすら収集していきます。ので、tasksとして実装していきます。
-
/fuel/app/tasks/streaming.php
を作成します。tasksファイルを作成して、処理を記述します。
/fuel/app/tasks/streaming.php<?php // Twitterstreaming namespace Fuel\Tasks; // phirehoseを読み込み require_once(APPPATH.'vendor/phirehose/lib/Phirehose.php'); require_once(APPPATH.'vendor/phirehose/lib/OauthPhirehose.php'); require_once(APPPATH.'vendor/phirehose/filter-oauth.php'); class Twitterstreaming { public static function run() { \Config::load('twitter', true); $api_setting = \Config::get('twitter.api_setting'); define("TWITTER_CONSUMER_KEY", $api_setting['consumer_key']); define("TWITTER_CONSUMER_SECRET", $api_setting['consumer_secret']); define("OAUTH_TOKEN", $api_setting['access_token']); define("OAUTH_SECRET", $api_setting['access_token_secret']); \Log::debug("Twitterstreaming : ---起動---"); // phirehoseでの処理 $sc = new \FilterTrackConsumer(OAUTH_TOKEN, OAUTH_SECRET, \Phirehose::METHOD_FILTER); $sc->setTrack(array('#ペット')); // 検索ワード $sc->setLang('ja'); // ロケール $sc->consume(); // 実行 } }
内容としては、ライブラリを読み込んで、認証情報を渡して、実行しているだけ。超シンプル。
-
/fuel/app/vendor/phirehose/filter-oauth.php
を作成続いてライブラリ側での処理を記述していきます。
/fuel/app/vendor/phirehose/filter-oauth.php<?php class FilterTrackConsumer extends OauthPhirehose { public function enqueueStatus($status) { // jsonをデコード $tweet = json_decode($status); // RTではなく、画像付きのツイートのみ if (isset($tweet->user->screen_name) && empty($tweet->retweeted_status) && !empty($tweet->extended_entities->media)) { // idは、intだとオーバーフローの恐れがあるので、文字列を使用 $post_id = $tweet->id_str; foreach($tweet->extended_entities->media as $media) { print $tweet->user->screen_name . ': ' . urldecode($tweet->text) . "\n"; // DBに保存 $model_sns_post = new \Model_Sns_Post; $model_sns_post->user_id = $tweet->user->screen_name; $model_sns_post->username = $tweet->user->name; $model_sns_post->post_id = $post_id; $model_sns_post->posted_date = date('Y-m-d H:i:s', strtotime($tweet->created_at)); $model_sns_post->url = 'https://twitter.com/' . $tweet->user->screen_name . '/status/' . $post_id; $model_sns_post->image_url = $media->media_url_https; $model_sns_post->image_w = $media->sizes->large->w; $model_sns_post->image_h = $media->sizes->large->h; $model_sns_post->comment = trim(str_replace($media->url, '', $tweet->text)); $model_sns_post->retweet_count = $tweet->retweet_count; $model_sns_post->favorite_count = $tweet->favorite_count; $model_sns_post->save(); } } } }
ちなみに、当初
json_decode($status, true)
としていましたが、「なぜtrue?」とのご指摘をいただきました・・・。たしかに、上記では配列にする必要はなさそうなので、修正しました。ありがとうございます!しかし、なぜtrueにしたんだ・・・。 -
実行してみる。
twitterstreamingを実行します。
php oil refine twitterstreaming
データベースに、続々とつぶやきが蓄積されています・・・。
もし、常時実行させる場合は、以下のような感じでしょうか。
nohup php oil refine twitterstreaming > /dev/null 2>&1 &
以上
超簡単でした・・・。
注意すべき点
1ツイートに複数画像が掲載されていた場合の考慮
画像情報は、$tweet['entities']['media']
と$tweet['extended_entities']['media']
の2種類あるが、entities
からは1画像分しか取得できない。ので、extended_entities
から取得するようにすること。
ちなみに、Twitter API 1.1 のsearch/tweets
では、entities
は取得できますが、extended_entities
は取得できません。
そう、1枚分の画像しか取得できません、なんと・・・。
Streamg API statuses/filterでの、キーワード検索の不思議な挙動
今回、「#ペット」というハッシュタグで検索しています。なので、以下のようなツイートは、当然収集できます。
我が家自慢のペットです! #ペット
これをたとえば「ペット」というキーワードにした場合、前述のツイートは取得できましたが、以下のようなツイートは取得できませんでした。
我が家自慢のペットです!
対象ワードの前後で文章が続いている場合、取得できませんでした。なんということでしょう・・・。ハッシュタグでの検索には有効かもしれませんが、単純なキーワード検索ということであれば、Twitter API 1.1 のsearch/tweets
を定期的に実行する方が良さそうです。
MySQLのエンコードがUTF-8だと、iOSの絵文字を含むツイートでINSERTエラー
iOSの絵文字をUTF-8で表すと、多くが4バイトです。そのため、文字コードがUTF-8のカラムにINSEERTしようとすると、華麗にエラーがでます。
Uncaught exception Fuel\Core\Database_Exception: SQLSTATE[HY000]: General error: 1366 Incorrect string value: '\xF0\x9F\x92\x96\xE2\x9C...' for column 'comment' at row 1 with query: "INSERT INTO `twitter` (`tweet`, `favorite_count`, `share_count, `updated_at`, `created_at`) VALUES ('#絵文字\n💖✨⭐️😘❤️💩😈💕😭😭😭💕💖', 0, 0, '2016-04-26 10:33:46', '2016-04-26 10:33:46')"
テーブルやカラムのエンコードを、utf8mb4にすることで、登録できるようになります。
ただし、表示はまた別の問題・・・。