Help us understand the problem. What is going on with this article?

Twitter gemでツイート検索する場合の要点、及び:since_id指定を有効にするモンキーパッチ

More than 3 years have passed since last update.

Twitter gem を使って検索する場合には注意しないと API 規制を受けてしまうことがあります。この記事では検索する場合の tips 、そして :since_id 指定していても API 規制を受けてしまうことを解決するモンキーパッチを公開します。

API上限

通常の認証:180回/15分(平均:5秒に1回まで)
Application-only auth:450回/15分(平均:2秒に1回まで)

アクセスクライアントインスタンスの作り方

通常の認証

require 'twitter'

client = Twitter::REST::Client.new(
  consumer_key:        'YOUR_CONSUMER_KEY',
  consumer_secret:     'YOUR_CONSUMER_SECRET',
  access_token:        'YOUR_ACCESS_TOKEN',
  access_token_secret: 'YOUR_ACCESS_SECRET',
)

Application-only auth

require 'twitter'

client = Twitter::REST::Client.new(
  consumer_key:        'YOUR_CONSUMER_KEY',
  consumer_secret:     'YOUR_CONSUMER_SECRET',
)

検索:Twitter::REST::Search#search(query, options = {})

optionsパラメータ:

標準

  • :geocode: 地点。"緯度,経度,距離"のフォーマットで指定。距離は mi または km 。
    例:"35.681382,139.766084,20km"(東京駅を中心とした半径20km以内。スペースを空けるとダメ)
  • :lang: 言語。 ISO 639-1コード で指定。
  • :locale: 地域。有効なのは "ja" のみ。
  • :result_type: 内容指定。デフォルトは "mixed"
    • "recent": 最近のツイート。
    • "popular": ポピュラーなツイート。
    • "mixed": popular と mix を混ぜたツイート。
  • :count: 取得数。デフォルトは15。最大は100。
  • :until: 指定日まで検索。"YYYY-MM-DD" のフォーマットで指定。ただし API では1週間までしか取得できず、 :until に1週間以前を指定してもやはり取得出来ない
  • :since_id: 指定 ID 以降から取得(最も古いツイート ID)。0または nil を指定すれば指定してない状況と同じ。 残念なことに、検索結果が100件以上ある場合には無効(検索結果が100件以上でも有効にするモンキーパッチを後記します)。
  • :max_id: 指定 ID 以前を取得(最も新しいツイート ID)。

query内での設定だがパラメータ指定も可能なもの

  • :from: 指定アカウントからのツイートを検索。アカウント名(screen_name)を指定する。
  • :to: 指定アカウントへのツイート(ただしツイート冒頭にある場合のみ)を検索。アカウント名(screen_name)を指定する。
  • :exclude: "retweets" を指定すると、検索結果から公式 RT を排除する。
  • :filter: "links" を指定すると、リンクを含むツイートのみを検索する。

参考:

検索例

query = "#ブラバンツなんたら" # 4/15の夜に *私だけ* が投稿したハッシュタグ。121ツイートあります。
since_id = nil
result_tweets = client.search(query, count: 100, result_type: "recent",  exclude: "retweets", since_id: since_id)
#=> #<Twitter::SearchResults:0x007ffb10d17cd0
     @attrs=
      {:statuses=>
        [{:metadata=>{:iso_language_code=>"ja", :result_type=>"recent"},
          :created_at=>"Wed Apr 15 15:39:04 +0000 2015",
          :id=>588365933179117568,
          :id_str=>"588365933179117568",
          :text=>"今気付いた、3位に汁だったんだw #ブラバンツなんたら",
    (略)

検索結果インスタンス result_tweets の取り扱い

検索結果が少ない((一週間以内の)検索可能範囲全体で100件未満の)場合(1回で全ての結果が取得できる場合)

result_tweets そのまま、もしくは result_tweets.to_a を対象にしてイテレータを使う。
検索結果が100件以上ある場合にこの方法を使うと API 規制を受ける場合があります。(詳細は後記)。

検索結果の全てが1回で取得出来ていない場合(検索可能範囲全体で検索結果が100件以上)

result_tweets.take(100) などで取得数を指定してイテレータを使う。take(1000) などと :count 指定数以上の数を指定した場合にも、指定数量を上限としたツイート数を取得してくれる。 take メソッドの代わりに、引数付き first メソッドでも OK 。

検索結果が多い場合に result_tweets.to_a を使うと

取得出来る(1週間以内のツイート) 全て の検索結果を取得しようとします。そのため、検索結果が非常に多い:count を100に設定していた場合、通常で最大18000件以上、Application-only authで最大45000件以上)場合には、 API を使い切るまでアクセスし、RateLimited エラーで終了してしまいます。しかも規制が掛からないようにと考えて :since_id を指定していても、その :since_id が検索2回目以降に含まれる範囲にある場合には :since_id 指定は有効になりません(要注意ポイント)。 これは Twitter gem のバグだと思います。
対策としては

  • take メソッドを使って取得数を決めてしまう
  • 後記するモンキーパッチ を当てて :since_id 指定を確実に有効にする

といった方法を用いましょう。

検索結果の各ツイートインスタンス Twitter::Tweet のメソッド例

各ツイートインスタンスを tw とします。

  • ID : tw.id
  • ツイート本文: tw.full_text
  • アカウント名: tw.user.name
  • スクリーンネーム: tw.user.screen_name
  • ツイート数 : tw.user.statuses_count
  • フォロー数 : tw.user.friends_count
  • フォロワー数: tw.user.followers_count
  • リツイート数: tw.retweet_count
  • お気に入り数: tw.favorite_count
  • 添付画像URL: tw.media.first.expanded_url.to_s
  • リンク先URL: tw.urls.map { |t| t.expanded_url.to_s }
    (リンク先を複数有する場合もあるので)

takeメソッドで取得数を指定してからイテレータを使う例

result_tweets.take(100).each_with_index do |tw, i| 
  puts "#{i}: @#{tw.user.screen_name}: #{tw.full_text}" 
end
#=> 0: @riocampos: 今気付いた、3位に汁だったんだw #ブラバンツなんたら
    1: @riocampos: パテルスキーもトップ10に入ったのか #ブラバンツなんたら
     :
    98: @riocampos: ルームポットのホーニヒ #ブラバンツなんたら
    99: @riocampos: あたっこ。ルームポット? #ブラバンツなんたら

100件取得されました。

取得数を指定せず検索結果インスタンスに対して直接イテレータを使う例

result_tweets.each_with_index do |tw, i| 
  puts "#{i}: @#{tw.user.screen_name}: #{tw.full_text}" 
end
#=> 0: @riocampos: 今気付いた、3位に汁だったんだw #ブラバンツなんたら
    1: @riocampos: パテルスキーもトップ10に入ったのか #ブラバンツなんたら
     :
    119: @riocampos: sporzaで #ブラバンツなんたら きた\o/
    120: @riocampos: #ブラバンツなんたら かなぁ

全件121件取得されました。

:since_id指定を有効にするモンキーパッチ

module Twitter
  class SearchResults
    def next_page
      return nil unless next_page?
      hash = query_string_to_hash(@attrs[:search_metadata][:next_results])
      since_id = @attrs[:search_metadata][:since_id]
      hash[:since_id] = since_id unless since_id.zero?
      hash
    end
  end
end

このモンキーパッチを使うと、 API へのアクセスが2回以上にわたる場合にも :since_id が有効になります( https://github.com/sferik/twitter/pull/682 でプルリクエスト提出済み)。

参考

本件に関してより詳しい内容はこちらに書いています。要点だけを Qiita に引用しました。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした