CFTraq.jp の機能追加としてソーシャルシェア数を取るようにしようと思う。現在、日次でクロールしてる案件は500件弱あるので、まとめて投げないとひどいことになる。ということでbatch request。
公式情報は以下
https://developers.facebook.com/docs/graph-api/making-multiple-requests
- 50リクエストまで一つのバッチにまとめて投げられるとのこと。
まずはCUIからcurlを使って試してみる
batch.sh
curl -s
-F 'access_token=***access_token***'
-F 'batch=[
{"method": "GET", "relative_url": "v2.3/?id=https://qiita.com/&fields=og_object{engagement},share"},
{"method": "GET", "relative_url": "v2.3/?id=http://kobito.qiita.com/&fields=og_object{engagement},share"}
]'
-F 'include_headers=false'
https://graph.facebook.com/ | jq '.'
# 実際には1行
curl -s -F 'access_token=***access_token***' -F 'batch=[{"method": "GET", "relative_url": "v2.3/?id=https://qiita.com/&fields=og_object{engagement},share"},{"method": "GET", "relative_url": "v2.3/?id=http://kobito.qiita.com/&fields=og_object{engagement},share"}]' -F 'include_headers=false' https://graph.facebook.com/ | jq "."
- curlに-sをつけて通信状況の表示を省略
-
-F 'batch=[{...}]'
の形式でバッチリクエストを記述 - 各リクエストは{}にJSONで記述。methodとrelative_urlは必須
-
&fields=og_object{engagement},share
を付けてるのはここを参照。 -
-F 'include_headers=false'
をつけてGraph APIから返ってくる時のヘッダーを省略 - (おまけ)最後に
jq '.'
でレスポンスのJSONを可視化している
レスポンスはこんな感じ。
response.json
[
{
"code": 200,
"body": "{\"og_object\":{\"engagement\":{\"count\":629,\"social_sentence\":\"629 people like this.\"},\"id\":\"143935272446719\"},\"share\":{\"comment_count\":0,\"share_count\":629},\"id\":\"https:\\/\\/qiita.com\\/\"}"
},
{
"code": 200,
"body": "{\"og_object\":{\"engagement\":{\"count\":304,\"social_sentence\":\"304 people like this.\"},\"id\":\"10150590829744321\"},\"share\":{\"comment_count\":0,\"share_count\":304},\"id\":\"http:\\/\\/kobito.qiita.com\\/\"}"
}
]
koalaを使ってrubyから投げてみる
rubyからGraph APIを叩くにはkoalaが便利。
batch.rb
# Graph APIはv2.3を使用
Koala.config.api_version = "v2.3"
# 単一のリクエスト
graph = Koala::Facebook::API.new("***access_token***")
graph.get_object("/", :id => "https://qiita.com/")
# バッチリクエスト
api = Koala::Facebook::API.new("***access_token***")
results = api.batch do |batch_api|
batch_api.get_object("/", :id => "https://qiita.com/")
batch_api.get_object("/", :id => "http://kobito.qiita.com/")
end
resultsの中身はこんな感じ。
results.rb
results
=> [{"id"=>"https://qiita.com/", "shares"=>550}, {"id"=>"http://kobito.qiita.com/", "shares"=>303}]
railsに組み込んでみる
koala wikiにちょうどrailsに使う際のやり方が載ってる。
https://github.com/arsduo/koala/wiki/Koala-on-Rails
koala.rb
#config/initializers/koala.rb
Koala::Facebook::OAuth.class_eval do
def initialize_with_default_settings(*args)
raise "application id and/or secret are not specified in the envrionment" unless ENV['FB_APP_ID'] && ENV['FB_APP_SECRET']
initialize_without_default_settings(ENV['FB_APP_ID'].to_s, ENV['FB_APP_SECRET'].to_s, args.first)
end
alias_method_chain :initialize, :default_settings
end
# Graph APIはv2.3を使用
Koala.config.api_version = "v2.3"
APP_IDとAPP_SECRETは環境変数で設定。
.sh
export FB_APP_ID='***fb_app_id***'
export FB_APP_SECRET='***fb_app_secret***'
# herokuなら以下
heroku config:set FB_APP_ID='***fb_app_id***'
heroku config:set FB_APP_SECRET='***fb_app_secret***'
使い方は以下のような感じ。
rails_koala.rb
urls = ["https://qiita.com/", "http://kobito.qiita.com/"]
graph = Koala::Facebook::API.new(Koala::Facebook::OAuth.new.get_app_access_token)
results = graph.batch do |batch_api|
urls.each { |url|
batch_api.get_object("/", :id => url)
}
end
resultsの中身はこんな感じ。
.rb
results
=> [{"og_object"=>{"id"=>"143935272446719", "description"=>"Qiitaは、プログラマのための技術情報共有サービスです。 プログラミングに関するTips、ノウハウ、メモを簡単に記録 & 公開することができます。", "title"=>"Qiita - プログラマの技術情報共有サービス", "type"=>"website", "updated_time"=>"2015-05-16T04:59:42+0000", "url"=>"https://qiita.com/"}, "share"=>{"comment_count"=>0, "share_count"=>630}, "id"=>"https://qiita.com/"}, {"og_object"=>{"id"=>"10150590829744321", "description"=>"エンジニアのためのMacアプリ「kobito」をQiitaが開発中!リリースまであと○○日…", "title"=>"Project ``kobito`` - ``kobito``先行利用ユーザー募集締切とニュースレター登録", "type"=>"website", "updated_time"=>"2015-05-11T11:24:27+0000", "url"=>"http://kobito.qiita.com/"}, "share"=>{"comment_count"=>0, "share_count"=>304}, "id"=>"http://kobito.qiita.com/"}]
Like数はresults[0]["share"]["share_count"]
とかでFixnumで取れる。