TwitterのGemを使ってFollowした人の一覧を取ろうとしたらちょっとハマった件


RubyのTwitter Gemで、TwitterのFollowした人一覧を表示しようとして少しハマったのでメモ。
使ったのはこれ。

息が長くメンテされているGemですね

普通にeachで回すとRate Limit Exceeded

twitter = Twitter::REST::Client.new do |config|
  config.consumer_key = ENV["CONSUMER_KEY"]
  config.consumer_secret = ENV["CONSUMER_SECRET"]
  config.access_token = ENV["ACCESS_TOKEN"]
  config.access_token_secret = ENV["ACCESS_TOKEN_SECRET"]
end

@friends = twitter.friends

こんな感じでフォローした人一覧を取得して、View側で

- @friends.each do |user|
  p = user.screen_name

のようなことをやると、いきなりRate Limit Exceededエラーを喰らいました。

これは、フォローしている人を取得するAPIの呼べる制限が15分に15回と定まっていて、1000人ぐらいフォローしている私のアカウントでやると
1000 / 20 = 50回、一瞬でコールしてしまうからですね。

20件に絞ってページングで随時取りたい

そもそも一回の取得で全件取りたいわけではなく、順次続きを読み込んでいくものを実装したかったのでそれのやり方を調べました。

twitter.friends.attrs

とやると、取得した20件のハッシュの配列が返ってきます。
この状態であれば、to_aしたりeachで回したりしても20件に絞られているのでAPIリクエストが発生しないのでエラーが出ずに表示できます。

しかし、アクセス方法が user.screen_nameではなくuser[:screen_name]のようになってしまうのがつらいです。

20件に絞ってhashではなくclassのインスタンスとしてアクセスしたい

twitter.friends.take(20)

のようにやると、20件返ってきて、Twitter::Userクラスのインスタンスなのでuser.screen_nameのようにアクセス可能です。

次の20件を取りたい

twitter.friends.attrsで返ってくるhashに、:next_cursorというものが含まれています。
これを使うと次の20件を取得することができます。具体的には、

twitter.friends(cursor: {next_cursorの値})

のように呼び出します。

ついでに、countという引数で取得件数を20〜200件の間で調整できるので、基本的に全friendsを舐めるようなサービスを作るのであれば200件取得した方がリクエスト数を減らすことができてAPI Rate Limitに達しにくくなります。

まとめると、最初のアクセス時は直近20件を取得し、「次へ」ボタンを押した時にその次の20件を取得する、の実装例としては以下のようになります。

  • controller
def TwitterFriendsController < ApplicationController
  FRIENDS_COUNT = 200.freeze

  def index
    response = twitter.friends(cursor: params[:cursor], count: FRIENDS_COUNT)
    @next = response.attrs[:next_cursor]
    @friends = response.take(FRIENDS_COUNT)
  end

  private

    def twitter
      @twitter ||= Twitter::REST::Client.new do |config|
        config.consumer_key = ENV["CONSUMER_KEY"]
        config.consumer_secret = ENV["CONSUMER_SECRET"]
        config.access_token = ENV["ACCESS_TOKEN"]
        config.access_token_secret = ENV["ACCESS_TOKEN_SECRET"]
      end
    end
end
  • view
/ @friendsをeachで回して表示するとかする
/ 
/ 次の200件を取得するボタン
= link_to "Next", twitter_friends_path(cursor: @next)