5
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

FuelPHPで、Twitter Streaming APIを使う

Posted at

概要

やりたいこと

Twitter Streaming APIのstatuses/filterを使って、特定のハッシュタグを含み、かつ画像付きのつぶやきを取得してウェブサイトに表示させたい。

環境

  • PHP 5.6.16
  • FuelPHP 1.7

事前準備

Twitterのアプリケーション登録

まずは、Twitter側でAPIを使えるようにしないと・・・。

  1. ということで、以下のURLにアクセス

    https://apps.twitter.com/

  2. 「Create New App」をクリックして、必要事項を入力していきます。

    • Name:アプリケーション名
    • Description:アプリケーションの説明
    • Website:アプリケーションのウェブサイト
    • Callback URL:コールバック用のURL

    最後に、英語の規約を頑張って読んで、「Yes, I agree」にチェックして、「Create Your Twitter application」をクリック。

  3. アプリケーションが登録されたら、「Key and Access Tokens」タブをクリック。「Consumer Key」と「Consumer Secret」を入手できます。

    「Consumer Secret」はほかの人に知られないよう、厳重に管理しましょう。

  4. 続いて、アクセストークンを取得します。同じ画面の下の方にある「Your Access Token」のなかに「Create my access token」というボタンがあるので、クリックしましょう。

    さっきまで何もなかった「Your Access Token」のなかに、「Access Token」と「Access Token Secret」が出現します。

ライブラリ「Phirehose」の用意

調べてみたなかで、比較的メジャーと思しき「Phirehose」というライブラリを使わせていただきます。

  1. Phirehoseをダウンロード

    https://github.com/fennb/phirehose

    ダウンロードしたら、解凍してphirehoseとかにリネームしたうえで、/fuel/app/vendorに放り込みましょう。

  2. 今回、statuses/filterを使うので、exampleフォルダの中にある、filter-oauth.phpを、あらかじめphirehose直下に移動しておきます。

実装

今回、常時実行プロセスで、つぶやきをひたすら収集していきます。ので、tasksとして実装していきます。

  1. /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();  // 実行
    	}
    }
    
    

    内容としては、ライブラリを読み込んで、認証情報を渡して、実行しているだけ。超シンプル。

  2. /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にしたんだ・・・。

  3. 実行してみる。

    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にすることで、登録できるようになります。
ただし、表示はまた別の問題・・・。

5
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?