やりたいこと
ここからPlayStation Network IDごとの成績、順位をまとめて取得したい。 通常だとスコア、アシスト、スティールなどの項目を個別に取得しなければならない。めんどくさい。 最初はCapybara/Phantomjsでスクレイピングしてみようと思ったけど、chromeの開発者ツールで通信を見てみるとJSON形式でPOSTすることで成績データを取得してるので、直接POSTを投げつけてみることに。
下準備
gem install open-uri
http/ftpでアクセスするためのライブラリ
プログラム
require 'net/http' require 'uri' require 'json' URL = "http://3on3rank.fsgames.com/rank" psnid = "成績を取得したいPSNID" set_total = 0 #0:シーズン成績 1:総合成績 error_code = 0 #0:正常終了 -10:サーバ接続エラー -20:PSNIDが誤っている # JSONでリクエストするデータ種別のハッシュ data_kind = { "Total Win" => 1, "Win Ratio" => 2, "Match Played" => 3, "MVP" => 4, "Avg. Score" => 5, "Avg. Rebound" => 6, "Avg. Block" => 7, "Avg. Steal" => 8, "Avg. Assist" => 9, "Avg. Looseball" => 10 } # 取得した成績データを格納するハッシュ record_data = { "Total Win" => nil, "Win Ratio" => nil, "Match Played" => nil, "MVP" => nil, "Avg. Score" => nil, "Avg. Rebound" => nil, "Avg. Block" => nil, "Avg. Steal" => nil, "Avg. Assist" => nil, "Avg. Looseball" => nil } # 取得した順位データを格納するハッシュ record_rank = { "Total Win" => nil, "Win Ratio" => nil, "Match Played" => nil, "MVP" => nil, "Avg. Score" => nil, "Avg. Rebound" => nil, "Avg. Block" => nil, "Avg. Steal" => nil, "Avg. Assist" => nil, "Avg. Looseball" => nil } # POSTするJSONのフォーマット payload = { "callType" => 1, "userID" => "#{psnid}", "userSN" => nil, "mode" => 2, "region" => 0, "period" => 2, "dataKind" => nil, "social" => 1, "curPage" => 1, "totalCount" => set_total, "platform" => 1 } uri = URI.parse(URL) http = Net::HTTP.new(uri.host, uri.port) req = Net::HTTP::Post.new(uri.request_uri) req["Content-Type"] = "application/x-www-form-urlencoded; charset=UTF-8" # httpリクエストヘッダの追加。追加しておかないと正常に応答してくれない data_kind.each do |data_kind_name, num| payload['dataKind'] = num req.set_form_data(payload) res = http.request(req) if res.code.to_i == 200 then json = JSON.parse(res.body) if json.dig('status') ==1 then record_data[data_kind_name] = json.dig('data', 0, 'DATA') record_rank[data_kind_name] = json.dig('data', 0, 'DATA_RANK') else error_code = -20 #"status==1"以外はPSNID誤りのためeachからbreak break end else error_code = -10 #レスポンスが"200 OK"以外の場合、eachからbreak break end end case error_code when 0 then # 取得したデータを正しい値に変更し出力 record_data['Win Ratio'] = ((record_data['Win Ratio']/100)) record_data['Avg. Score'] = ((record_data['Avg. Score'].to_f/10000)).round(3) record_data['Avg. Rebound'] = ((record_data['Avg. Rebound'].to_f/10000)).round(3) record_data['Avg. Block'] = ((record_data['Avg. Block'].to_f/10000)).round(3) record_data['Avg. Steal'] = ((record_data['Avg. Steal'].to_f/10000)).round(3) record_data['Avg. Assist'] = ((record_data['Avg. Assist'].to_f/10000)).round(3) record_data['Avg. Looseball'] = ((record_data['Avg. Looseball'].to_f/10000)).round(3) puts "Season Result(DATA) : #{record_data}" puts "Season Result(RANK) : #{record_rank}" when -10 then puts "サーバに接続できません" when -20 then puts "入力されたPSNIDの成績が存在しません" end
ハッシュから値を取り出す場合、digを利用すると便利。 https://docs.ruby-lang.org/ja/latest/method/Hash/i/dig.html
json = JSON.parse(res.body)
でPOSTの結果をJSONとして解析して、ハッシュに変換
実行結果
root@hostname:/tmp# ruby posttest.rb Season Result(DATA) : {"Total Win"=>50, "Win Ratio"=>73, "Match Played"=>68, "MVP"=>25, "Avg. Score"=>10.706, "Avg. Rebound"=>2.426, "Avg. Block"=>0.809, "Avg. Steal"=>0.956, "Avg. Assist"=>2.603, "Avg. Looseball"=>1.5} Season Result(RANK) : {"Total Win"=>3437, "Win Ratio"=>806, "Match Played"=>4654, "MVP"=>1978, "Avg. Score"=>583, "Avg. Rebound"=>2223, "Avg. Block"=>4118, "Avg. Steal"=>828, "Avg. Assist"=>2149, "Avg. Looseball"=>7347}
参考文献
https://qiita.com/toshihirock/items/19fc868d3c4c52411aa9 https://dev.classmethod.jp/client-side/take_care_when_using_the_to_json/ https://qiita.com/seisonshi/items/c23c0154c45ccbfa9999 http://ruby-doc.org/stdlib-2.1.5/libdoc/net/http/rdoc/Net/HTTP.html https://qiita.com/Mocacamo/items/8c8d2cdab3e2210971e0 https://qiita.com/vzvu3k6k/items/1705c7f4b29c08787ea0 https://qiita.com/nishina555/items/48cfc3eb80a78cbe51b9 https://qiita.com/taigamikami/items/d67e96479450958c2a39 https://docs.ruby-lang.org/ja/latest/method/Float/i/round.html https://qiita.com/ryoff/items/0eb270fbc8de96cf158f