1. riocampos

    No comment

    riocampos
Changes in body
Source | HTML | Preview
@@ -1,140 +1,140 @@
-Twitter gem を使って検索する場合には注意しないと API 規制を受けてしまうことがあります。この記事では検索する場合の tips 、そして :since_id 指定していても API 規制を受けてしまうことを解決するモンキーパッチを公開します。
+Twitter gem を使って検索する場合には注意しないと API 規制を受けてしまうことがあります。この記事では検索する場合の tips 、そして `:since_id` 指定していても API 規制を受けてしまうことを解決するモンキーパッチを公開します。
#API上限
通常の認証:180回/15分(平均:5秒に1回まで)
Application-only auth:450回/15分(平均:2秒に1回まで)
#アクセスクライアントインスタンスの作り方
##通常の認証
```rb
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
```rb
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 。<br>例:`"35.681382,139.766084,20km"`(東京駅を中心とした半径20km以内。スペースを空けるとダメ)
- `:lang`: 言語。 [ISO 639-1コード](http://ja.wikipedia.org/wiki/ISO_639-1%E3%82%B3%E3%83%BC%E3%83%89%E4%B8%80%E8%A6%A7) で指定。
- `: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"` を指定すると、リンクを含むツイートのみを検索する。
参考:[Twitter 検索API メモ - 超自己満足プログラミング](http://d.hatena.ne.jp/favril/20090327/1238138002)
#検索例
```
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 }`<br>(リンク先を複数有する場合もあるので)
###`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`指定を有効にするモンキーパッチ
```rb
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 でプルリクエスト提出済み)。
#参考
- [Twitter gemを使って検索するときのtips - 別館 子子子子子子(ねこのここねこ)](http://d.hatena.ne.jp/riocampos+tech/20150421/twitter_gem_search_tips)