Twitter Apiでツイートを検索・表示

DIY

前回まででOpenWeatherApiから「現在の天気」が取得・表示できました。

次はツイッターから必要なデータを探してブラウザ表示させるまでを実装してゆきます。

準備

パッケージインストール

composer require abraham/twitteroauth

でパッケージをインストールしておいてください。

ルーティング

/api/tweets にGETアクセスすると、getTweetsメソッドに来るよう定義します。

Route::get('/tweets', [TwitterController::class, 'getTweets']);

※api.php に設定したルートは、自動でurlに/apiが付与されるので実際のapiアクセス先は、/api/tweets となります

Twitter Api接続に必要なデータをconfigに追記

コントローラーで使いたいapi接続情報を、/config/const.php に追記します

OpenWeather用データの下に、twitter用のデータを書いています。

.envに本当のデータを定義して、configで.envを呼び出している形になります。

これをコントローラーで呼び出す部分は以下の通りです。

複数メソッドでツイッターに接続するので、__construct内でまとめて定義しています。

Serach Tweetの基本的な使い方

$tweetList = $this->connection
       ->get('/search/tweets', $tweets_params)
       ->statuses;

上記でツイートが取得できます。

$this->connection : コンストラクタでnewしたTwitterOAuthインスタンスが入っています

->get(‘/search/tweets’, $tweets_params): 第一引数にurlを、第二引数に検索条件が入っています

↑↑この$tweet_paramsは、検索したい条件の配列です。以下のような値を定義しています。

$tweets_params = [
    'q' => '東京 天気',   //検索したいキーワード
    'count' => 10,  //取得件数。デフォルトは15件
];

‘q’以外は任意なので、必要に応じて変更してください。

その他のパラメーターはこちら

返ってくるデータ

$this->connection->get(‘/search/tweets’, $tweets_params);

このコードで返ってくるデータは

こんな風にstatuses配下に収まっています。

なので取得時に ->statuses を書いておくことで、ひとつ階層を浅くできるので(satussesを省ける)書いておいたほうが後で楽だと思います。

エラー時

ちなみにエラー時は

errors が返ってきます。

実際に書いたツイッター取得用のコード(Controller)

上は基本的な使い方ですが、今回は天気・食べ物の2種類分apiを叩きたかったので
変数でキーワードを渡すなどして最終的に以下のようになりました。

ユーザー画面での、Osaka, Sapporo などselectBoxでの値変更がトリガーとなっています。

  App\Http\Controllers\Api\TwitterController 内


 public function getTweets(Request $request)   // ajaxでここに来る
    {
        $destination = $request->destination;

   //天気関連ツイート取得
        $tweetWeatherList = $this->getTweetByKeywords($destination, '#イマソラ');
  
  //食べ物関連ツイート取得
        $tweetFoodList = $this->getTweetByKeywords($destination, '美味しい');

        return response()->json(   // jsonをJS側に返す
            [
                'weather' => $tweetWeatherList,
                'food' => $tweetFoodList,
            ]
        );
    }

    private function getTweetByKeywords($destination, $keyword) //実際のデータ取得関数
    {
   //検索キーワードを設定。 -をつけると除外検索ができる
        $q =  $destination . $keyword . ' -相互 filter:images -#相互RT exclude:retweets';

        $tweets_params = [
            'q' => $q,
            'count' => config('const.api.twitter.settings.getNum'),
            'tweet_mode' => 'extended', 
        ];
       
        $tweetList = $this->connection->get('/search/tweets', $tweets_params)->statuses;
        
    //以下はbladeで画像を表示させるための準備なので
   //必要ない場合もあります
        foreach ($tweetList as $tweet) {
            $tweet->mediaUrl = '画像なし';  //初期値

            //画像urlを取得
            $mediaExist = $tweet->extended_entities->media ?? '';

            if ($mediaExist) {
                $media = $tweet->extended_entities->media;
                foreach ($media as $m) {
                    if ($m->type === 'photo') {
                        $tweet->mediaUrl = $m->media_url_https;
                    }
                }
            }
        }

        return $tweetList;
    }

これでJSからPHP側に値が渡ってきた場合の処理はかけましたので、JS側を書いてゆきます。

BladeからJS、JSからAjax送信

順番が前後しますが、フロント側の実装です。

ブラウザでselectBoxが選択された(changeイベント発生)がトリガーとなり、ajaxが走ります。

ajax

以下ajax部分のみ抜粋。

    $.ajax({
      headers: {
        'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content'),
      },
      url: '/api/tweets',   // api.phpに定義したルート 
      type: 'GET',
      data: {
        'destination': destination  // selectboxで選ばれた地域名が入る
      },
      dataType: 'json',
    })
      .done(function (response) {
     
      const makeTweetHtml = function (index, tweet) {

          var block = '<div class="col">'
            + '<a href="https://twitter.com/' + tweet.user.screen_name + '/status/' + tweet.id_str + '" class="test-dark" target="_blank">'
            + '<p>画像:<img src="' + tweet.mediaUrl + '" class="img-fluid"></p>'
            + '<p>ツイート内容:' + tweet.full_text + '</p></a>'
            + '</div>';

          targetDom.append(block);
        }

        //
        //天気
        //
        var targetDom = $('#js_tweetWeatherWrap')
        targetDom.html(""); //前回の取得内容をリセット
        $.each(response.weather, makeTweetHtml)

        //
        //食べ物
        //
        var targetDom = $('#js_tweetFoodWrap')
        targetDom.html(""); //前回の取得内容をリセット
        $.each(response.food, makeTweetHtml)

      })
      .fail(function () {
        console.log("failed");
      })

これで、セレクトボックスで選んだ地域名のお天気関連ツイート、食べ物関連ツイートがブラウザに表示されます。

食べ物関連ツイートは見切れていますが、ちゃんと設定した件数表示されています。

cssは未実装同然なのでどうにかしたいのですが、その前にこれをVue.jsに書き換えてから。。

実際考えながら書いていると時間がかかりましたが、まとめると1ページで収まるくらいシンプルですね。

タイトルとURLをコピーしました