Serverless CLI を使って AWS Lambda + API Gateway から 特定のハッシュタグの Tweets を取得する方法 (Twitter API を app auth で使ったメモ)

タイトル通り。

勉強会で Tweet をしてもらった後、それをみんなで見ながら「わいわい」するために 勉強会用のハッシュタグの Tweet を一覧化したかった。

実際に使用した勉強会の配信動画 “ゆるWeb勉強会@札幌 OnLine #8”

公式の埋め込みタイムラインなどは、ハッシュタグに対応していない。

なので、自分で作りました。

今回の本題は、特定のハッシュタグの Tweets を取得するところ。

ライブラリなども揃っていて難しいことは無いけど、キーなどを生成する手順が(個人的に欲しいサイズで)まとまっていなかったので、書いておく。

やりたいのは、 Twitter API のうち Standard Search APIapp auth で使うこと。
これによって、無料の範囲でできるだけ高頻度に Tweets の検索を実行できる。
(15分の間に 450回 のリクエストが可能。2秒に一回のリクエストまで可能。)

これを使うためには、 Consumer API keysAPI keyAPI secret key 、それらから生成する Bearer Token の3つが必要となる。

前提

$ serverless -v
Framework Core: 1.79.0
Plugin: 3.7.1
SDK: 2.3.1
Components: 2.34.6
$ node -v
v12.4.0
$ yarn -v
1.22.4
$

手順

Twitter API の各種キー取得・作成

Twitter Developerアプリケーション一覧ページCreate an app から、アプリを作成する。
(詳しいのは検索すれば出てきます。)

作成できれば、 Keys and tokens タブから必要な情報が得られる。

まずは、ここで Consumer API keysAPI keyAPI secret key を確認。

コンソールで curl を使い Bearer Token を生成

https://developer.twitter.com/en/docs/authentication/oauth-2-0/bearer-tokens
curl -u "$API_KEY:$API_SECRET_KEY" \
  --data 'grant_type=client_credentials' \
  'https://api.twitter.com/oauth2/token'

結果、下記のような JSON が得られる。

{"token_type":"bearer","access_token":"AAAAAAAAAAAAAAAAAAAAAMLheAAAAAAA0%2BuSeid%2BULvsea4JtiGRiSDSJSI%3DEUifiRBkKG5E2XzMDjRfl76ZC9Ub0wnz4XsNiRVBChTYbJcE3F"}

これの "access_token" の値を使う。

プロジェクト作成

$ serverless create --template aws-nodejs -p twhash
$ cd twhash
$ yarn add twitter

serverless.yml

service: twhash

provider:
  name: aws
  runtime: nodejs12.x
  stage: dev
  region: ap-northeast-1

functions:
  twhash:
    handler: handler.twhash
    events:
      - http:
          path: twhash/{hashTag}/{sinceId}
          method: get
          request:
            parameters:
              paths:
                hashTag: true
                sinceId: true
    environment:
      CONSUMER_KEY: 'YOUR_CONSUMER_KEY'
      CONSUMER_SECRET: 'YOUR_CONSUMER_SECRET'
      BEARER_TOKEN: 'YOUR_BEARER_TOKEN

hashTag に検索したハッシュタグ(をURLエンコードしたもの)、 sinceId に検索の起点となる Tweet の ID を指定する。

取得結果の中 search_metadata.max_id_str を指定すると、取得後の新しい Tweets を取得できる。

handler.js

'use strict';
const Twitter = require('twitter')

const client = new Twitter({
  consumer_key: process.env.CONSUMER_KEY,
  consumer_secret: process.env.CONSUMER_SECRET,
  bearer_token: process.env.BEARER_TOKEN
})

const getTweets = function (params) {
  return new Promise((resolve, reject) => {
    client.get('search/tweets', params, function(error, tweets, response) {
      if (!error) {
        resolve(tweets)
      } else {
        console.error(error)
        reject(error)
      }
    });
  })
}

module.exports.twhash = async event => {
  const hashTag = decodeURIComponent(event.pathParameters.hashTag)
  const sinceId = event.pathParameters.sinceId ? event.pathParameters.sinceId : '0'
  console.log(hashTag, sinceId)
  const params = {q: hashTag, since_id: sinceId, count: 100, result_type: 'recent'};

  const tweets = await getTweets(params)
  return {
    statusCode: 200,
    headers: {
      'Access-Control-Allow-Origin': '*'
    },
    body: JSON.stringify(tweets)
  }
}

getTweets() でAPIから結果を取得し、そのまま返すだけのコード。

受け取ったフロントエンドで、自由に加工して表示すればOK。

結果

今回のイベントの “#ゆるWeb札幌” を検索してみる。

$ curl https://XXXXXXXXXX.execute-api.ap-northeast-1.amazonaws.com/dev/twhash/%23%E3%82%86%E3%82%8BWeb%E6%9C%AD%E5%B9%8C/0
{"statuses":[{"created_at":"Wed Aug 26 12:03:46 +0000 2020","id":1298591969879326700,"id_str":"1298591969879326723","text":"RT @tacck: ゆるWeb勉強会@札幌 OnLine #8 / #ゆるWeb札幌 - Togetter https://t.co/TLWa93Eke1 @togetter_jpより \n\n遅くなりましたが、8/24のまとめ作成しました!","truncated":false,"entities":{"hashtags":[{"text":"ゆるWeb札幌","indices":[35,43]}],"symbols":[],"user_mentions":[{"screen_name":"tacck","name":"t a c c k 🏡 Kihara, Takuya","id":6475652,"id_str":"6475652","indices":[3,9]},{"screen_name":"togetter_jp","name":"Togetter公式","id":72555864,"id_str":"72555864","indices":[79,91]}],"urls":
...(snip)...
,"search_metadata":{"completed_in":0.159,"max_id":1298591969879326700,"max_id_str":"1298591969879326723","next_results":"?max_id=1297858994791313411&q=%23%E3%82%86%E3%82%8BWeb%E6%9C%AD%E5%B9%8C&count=100&include_entities=1&result_type=recent","query":"%23%E3%82%86%E3%82%8BWeb%E6%9C%AD%E5%B9%8C","refresh_url":"?since_id=1298591969879326723&q=%23%E3%82%86%E3%82%8BWeb%E6%9C%AD%E5%B9%8C&result_type=recent&include_entities=1","count":100,"since_id":0,"since_id_str":"0"}}
$

このような感じで、手軽に検索結果を取れるようになる。

フロントはこのようなイメージで出せる。

tacck
  • tacck
  • 北の大地の普通のソフトウェアエンジニア。
    インフラ・バックエンド・フロントエンドと、色々やります。

    初心者・若手向けのメンターも希望あればお受けします。

    勉強会運営中
    * ゆるWeb勉強会@札幌
    * スマートスピーカーで遊ぼう会@札幌

コメントする

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください