ばーろぐわにる

SIerからWEB系?インフラエンジニアにジョブチェンジした見習いの備忘録。投稿内容は私個人の意見であり、所属企業・部門見解を代表するものではありません。

RubyであるサイトにPOSTして結果を出力する

やりたいこと

ここから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