TwitterAPI でツイートを大量に取得。サーバー側エラーも考慮(pythonで)

TwitterAPI を利用してツイートを大量にダウンロードしてみます。ダウンロードしたツイートを MeCab や Word2vec の元ネタにするつもりですが、とりあえず、データ取得の部分にしぼって書いてみます。

前半は API の基本事項の説明なので、そんなのもう知ってるよ、な方は 後半の 「大量にダウンロード」 にとんでください。

- 目次 -

スポンサーリンク

TwitterAPI とは

ツイートを投稿、閲覧するための API です。簡単に利用できるので、ツイッターにアクセスする独自アプリケーションを手軽に作成できます。

TwitterAPI を利用するには

  • アプリケーションの登録
  • 4つの認証キー取得

が必要にになります。
手順はいろいろなサイトで紹介されていますが、たとえば ここ で確認できます。

仕組み

REST形式で要求を出し、JSON形式で結果を受け取るのが基本的な仕組みです。用途に応じて様々なエンドポイントが定義されており、パラメータもそれぞれ異なります。いくつか例をあげると

●キーワードを指定してツイートを取得したければ

URL https://api.twitter.com/1.1/search/tweets.json
必須パラメータ q : 検索ワード

●特定ユーザーのツイートをまとめて取得したければ

URL https://api.twitter.com/1.1/statuses/user_timeline.json
必須パラメータ user_id : ユーザーID
 または
screen_name : スクリーン名(@で表示される名称)

●ツイートを投稿したければ

URL https://api.twitter.com/1.1/statuses/update.json
必須パラメータ status : 投稿ツイート

オプションのパラメータとして

  • count
    取得件数を指定します。
  • max_id
    ツイートID の最大値を指定します。
    大量のツイートを取得する場合、一度に取得できるツイート数は限られているので、何度もリクエストを出すことになります。その際 max_id を指定すると、前回取得したツイートの次からを取得対象にできます。

取得データ

取得データは ステータスコード、ヘッダー部、テキスト部に別れます。

ステータスコード

API 呼出しの正常・異常終了はステータスコードで判定します。200 が正常終了を意味します。

ヘッダー部

ヘッダ部には以下に説明する制限情報がのっています。

制限情報とは

TwitterAPI には一定時間内にアクセスできる回数に上限があります。
たとえば、キーワードで検索する

https://api.twitter.com/1.1/search/tweets.json

は 15 分間に 180 回までと決まっており、この規定回数を超えてアクセスするとエラーになります(コード:429)。もちろん永遠にアクセスできないわけではなく、15 分毎にアクセス制限はリセットされます。

そうした制限に関する情報がヘッダ部にのっており、以下のキーで取得できます。

  • X-Rate-Limit-Remaining
    アクセス可能回数 (アクセスするごとに -1 されていきます)
  • X-Rate-Limit-Reset
    アクセスが可能になるまでの時間 (アクセス可能回数が 0 になっても、この値の時間まで待てば回数はリセットされます)

補足

制限情報を確認するための専用エンドポイントもあります。
https://api.twitter.com/1.1/application/rate_limit_status.json

一発目の検索前にアクセス可能回数を調べるという手堅い実装をするなら、このエンドポイントが便利です。
こちらのソース の checkLimit で使ってます。

テキスト部

取得したツイートはテキスト部にのっています。テキスト部のフォーマットはエンドポイントによって差異があるので、ツイートを取り出す際は注意が必要です。
たとえば

  • キーワード検索(https://api.twitter.com/1.1/search/tweets.json)の場合
    ⇒ テキスト部の statuses の下にツイートが置かれる
  • ユーザー名で検索(https://api.twitter.com/1.1/statuses/user_timeline.json)の場合
    ⇒ テキスト部の直下にツイートが置かれる

という違いがあります。

取得データ フォーマットイメージ

以下はキーワード検索時の取得データのフォーマット(ごく一部の抜粋)です。ユーザー名で検索した場合は statuses という項目そのものが存在せず、テキスト部直下にツイートがぶら下がっています。
twitter APIのレスポンス

retweeted_status は
リツイート時のみセットされる

コピペ用

status_code
headers
┗ X-Rate-Limit-Remaining
┗ X-Rate-Limit-Reset
text
┗ statuses
   ┗ text
   ┗ id
   ┗ user
     ┗ screen_name
     ┗ followers_count
   ┗ created_at
   ┗ retweeted_status
     ┗ text
     ┗ id

サンプル

簡単なサンプルをコーディングしてみます。

ツイート取得

以下で、”沖縄旅行” を含むツイートを 10 件取得できます。

ツイート投稿

投稿は以下で OK。

◇◇◇

基本事項の説明はここまでです。次節でデータのダウンロードに取りかかります。

大量にダウンロード

ここからが本題ですが、ツイートを大量に取得するためのプログラムを作ります。一回に取得できる件数は 100 とか 200 件程度の上限があるので、ループしながら API 呼出しを繰り返すことになります。ただし、回数制限があるので、ひたすら API を呼び続けるわけにはいかず、考慮が必要です。

方針として

  • 「キーワードで取得」 と 「ユーザーを指定して取得」 の2機能を備える
  • ツイートは一件づつ yield する
  • 回数制限に到達したら、制限解除まで sleep し、解除後に再開する

ことにします。

クラスは3つ。

TweetGetter クラス図

ソース

このまま実行すれば “渋谷” をふくむツイートが 3000 件取得できます。
コメントを入れ替えれば “AbeShinzo” さんのツイートが取得できます。

オプション

collect メソッドの引数で以下の 3 点が指定可能。

  • total : 取得件数
    デフォルト -1 (無制限に取得。ただし Twitter 側の設定する上限がある)
  • onlyText : メッセージ本文だけ取得する
    デフォルト False
  • includeRetweet : リツイートを含める
    デフォルト False

エラー対策

サーバー側に起因するなんらかの理由でエラーが発生する場合があります。以下、対処法です。

Service Unavailable

status_code:503

サーバー側の処理が追いつかない場合に発生します。しばらく sleep してアクセスを再開すれば問題ありません。必要な sleep 時間はサーバーの状況によると思いますが、今まで見た範囲では 30 秒の sleep で大丈夫でした。

Too Many Requests

status_code:429

180回/3分 等の回数制限を無視してアクセスすると発生します。
X-Rate-Limit-Remaining を確認しながらアクセスすれば通常は発生しません。

正しい手順として、X-Rate-Limit-Remaining が 0 になった場合は X-Rate-Limit-Reset まで sleepします。ただし、sleep 時間が微妙にサーバーとずれる可能性があるため、アクセスを再開する前に下記のエンドポイント

https://api.twitter.com/1.1/application/rate_limit_status.json

remaining (アクセス可能回数)
reset        (アクセスが可能になるまでの時間)

を確認します。

X-Rate-Limit-Remaining が入ってない

理由は不明ですが、レスポンスに X-Rate-Limit-Remaining が入ってないことが稀にあります。そうしたケースでは、下記のエンドポイント

https://api.twitter.com/1.1/application/rate_limit_status.json

remaining (アクセス可能回数)
reset        (アクセスが可能になるまでの時間)

を確認します。

スポンサーリンク
その他の記事
    • あ、抜けてますね。しかも、ところどころ。。。

      直しました。

      2.7 で動かしてるので、すぐ括弧を忘れてしまいます。
      ありがとうございました。

  1. プログラム大変参考にさせてもらっています。
    質問なのですが
    idを取得してidの人の自己紹介文を取得することは可能ですか?

    • こんな感じでしょうか。

      ① ツイートから id を取得する
      tweet['id']

      ② id からユーザー情報を取得する(別途、リクエスト)
      url = 'https://api.twitter.com/1.1/users/show.json'
      params = {'user_id':'xxxxxxxxx'}
                   ↑
                 ①で取得したやつ

      res = session.get(url, params = params)

      ③ 自己紹介を取りだす
      t = json.loads(res.text)
      print (t['description'])

      ======================
      ちなみに

      安倍さんの自己紹介はこれで取得できました。

      url = 'https://api.twitter.com/1.1/users/show.json'
      params = {'user_id':'468122115'}
      res = session.get(url, params = params)

      t = json.loads(res.text)
      print (t['description'])

  2. 分かりやすい記事をありがとうございます。

    大量にツイートを取得する際は最近のツイートしか取得できないという使用でしょうか。

    キーワードによっては取得件数が少ししか取れないものもあるようでして

    お願いします。

    • tas さん、どうも。

      ネットの情報ですが、APIでは過去1週間のツイートしか取れないようです。
      キーワードによっては、ほとんどツイートがないケースもあるかもしれませんね。

  3. 管理人様

    回答頂きありがとうございます。
    ツイートID で過去の記事を取得するとかありますね。

    streamingAPI をずっと動かしつづけるしかないのでしょうか・・・(T_T)

  4. 管理人様
    tweetの投稿された位置情報(投稿場所情報)を同時に取得するにはどのようにすればよろしいでしょうか?

    • yuさん、こんにちわ

      coordinates という項目に経度、緯度が入るようです。
      掲載ソースの場合、こうなります。(インデントがうまく入ってませんが)

      if tweet['coordinates'] is not None:
      print (tweet['coordinates']['coordinates'][0]) # 経度
      print (tweet['coordinates']['coordinates'][1]) # 緯度

      位置情報付きでつぶやく人は少ないので、実際に coordinates に値が入るツイートも少ないようです。

コメントはお気軽に