結論
あるAPIを残り何回叩けるか、いつ制限がリセットされるか
などの情報を取得できるTwitter APIがあるので、そいつから取得した情報を元に制限一杯まで実行すれば良い。
このAPI:
dev.twitter.com
背景
やりたい事
あるTwitterアカウントをフォローしているユーザー
がその他にどんなアカウントをフォローしているのか
を調べたい。
最初に試した方法
あるTwitterアカウントをフォローしているユーザー
を取得したのち、それぞれのユーザーに対してフォローしているアカウント
の一覧を取ろうとした。
- ruby gemのにTwitter APIをいい感じにラップしてくれるやつがあったので、それを使った。
github.com
最初に試した方法の課題点
あるTwitterカウントのフォロワー数
分APIを叩く事になる。
- twitter APIには非常に厳しい実行回数制限がある。
- 実行回数の制限に引っかかると、例外を吐いてプログラムが終了するので全然はかどらない。
参考:
Rate Limits: Chart | Twitter Developers
対策
あるAPIを残り何回叩けるか、いつ制限がリセットされるか
などの情報を取得できるTwitter APIがあるので、そいつから取得した情報を元に制限一杯まで実行する。
実装
require 'twitter'
class APILimitStatus
def initialize(client, target_end_point, target_api)
@client = client
@target_end_point = target_end_point
@target_api = target_api
setup_or_update_limit_status!
check_arguments!
end
def sleep_to_reset_if_limit!
setup_or_update_limit_status!
if remaining <= 0
sleep(need_seconds_for_reset)
end
end
private
def need_seconds_for_reset
now = Time.now.to_i
(reset_at - now) > 0 ? (reset_at - now) : 0
end
def reset_at
@limit_status[@target_end_point][@target_api][:reset]
end
def remaining
@limit_status[@target_end_point][@target_api][:remaining]
end
def setup_or_update_limit_status!
limit_status = @client.__send__(:perform_get, '/1.1/application/rate_limit_status.json')
@limit_status = limit_status[:resources]
end
def check_arguments!
raise if @limit_status[@target_end_point].nil?
raise if @limit_status[@target_end_point][@target_api].nil?
end
end
client = Twitter::REST::Client.new do |config|
config.consumer_key = ""
config.consumer_secret = ""
config.access_token = ""
config.access_token_secret = ""
end
SURVEY_USER_ID = "hoge"
follower_api_limit = APILimitStatus.new(client, :followers, :"/followers/ids")
follower_api_limit.sleep_to_reset_if_limit!
follower_ids = client.follower_ids(user_id: SURVEY_USER_ID).attrs[:ids]
follower_ids.shuffle!
friend_api_limit = APILimitStatus.new(client, :friends, :"/friends/ids")
follower_ids.each do |follower_id|
friend_api_limit.sleep_to_reset_if_limit!
begin
friend_ids = client.friend_ids(user_id: follower_id).attrs[:ids]
puts "#{follower_id},#{friend_ids.to_s}"
rescue Twitter::Error => e
puts "#{follower_id},#{e.to_s}"
end
end