はじめに
楽天トラベルにてとあるホテル料金をブラウザで検索していた際、URLにて入力情報を管理している仕組みに気づいたのでcurlコマンドで日付をずらしながら料金を取得するスクリプトを作ってみました。本記事ではその備忘録です。
利用コマンド
$ curl --version curl 7.52.1 (x86_64-pc-linux-gnu) libcurl/7.52.1 OpenSSL/1.0.2u zlib/1.2.8 libidn2/0.16 libpsl/0.17.0 (+libidn2/0.16) libssh2/1.7.0 nghttp2/1.18.1 librtmp/2.3 Protocols: dict file ftp ftps gopher http https imap imaps ldap ldaps pop3 pop3s rtmp rtsp scp sftp smb smbs smtp smtps telnet tftp Features: AsynchDNS IDN IPv6 Largefile GSS-API Kerberos SPNEGO NTLM NTLM_WB SSL libz TLS-SRP HTTP2 UnixSockets HTTPS-proxy PSL
楽天トラベルのURL体系
例えば群馬県の水上山荘というホテルを4/1~4/2の一泊二日で男性一人で検索するとURLは以下となります。
https://search.travel.rakuten.co.jp/ds/vacant/searchVacant?f_chu=gunma&f_shou=numata&f_sai=&f_hi1=1&f_tuki1=4&f_nen1=2020&f_hi2=2&f_tuki2=4&f_nen2=2020&f_no=134873&f_kin=&f_kin2=0&f_tab=plan&f_sort=kin&f_heya_su=1&f_otona_su=1&f_s1=0&f_s2=0&f_y1=0&f_y2=0&f_y3=0&f_y4=0&f_kaiin_no=&f_kaiin_tel=&f_jyoken=no&f_cd=03&f_dai=japan&f_image=1&f_page=1&f_hyoji=30&ref=info
検索結果は以下のようにブラウザ上に表示されます。
ここでポイントはURLの
f_hi1
にチェックイン日
f_hi2
にチェックアウト日が入っています。
楽天トラベルのHTML体系
HTMLを表示すると以下のように検索結果がJSON形式で格納されています。
var ds = {"actionPath":"searchVacant","areaName":"水上・猿ヶ京・沼田","conditions":{"f_no":["134873"],"f_sort":["hotel_kin_low"],"f_campaign":[""],"f_point_min":["0"],"f_page":["1"],"seo_f_chu":[""],"seo_f_shou":[""],"f_gcode":[""],"f_cd":["03"],"f_dai":["japan"],"f_chu":["gunma"],"f_shou":["numata"],"f_sai":[""],"f_latitude":["0.0"],"f_longitude":["0.0"],"f_km":[""],"f_squeezes":[],"f_rm_bed":[],"f_rm_type":[],"f_tab":["hotel"],"f_service":null,"f_nen1":["2020"],"f_tuki1":["04"],"f_hi1":["01"],"f_nen2":["2020"],"f_tuki2":["04"],"f_hi2":["02"],"f_otona_su":["1"],"f_s1":["0"],"f_s2":["0"],"f_y1":["0"],"f_y2":["0"],"f_y3":["0"],"f_y4":["0"],"f_heya_su":["1"],"f_kin":[""],"f_kin2":["0"],"f_ido":["0.0"],"f_kdo":["0.0"],"f_teikei":[""],"f_disp_type":[""],"f_hyoji":["30"],"f_image":["1"],"f_setubi":[""]},"displayedHotels":[134873],"facilityName":"谷川温泉 檜の宿 水上山荘","hotels":{"134873":{"plans":{"3327372":{"rooms":{"newb":{"sumTotalChargeTaxExclusive":18000,"sumTotalChargeTaxInclusive":19800,"taxType":"exclusive"}}},"3327371":{"rooms":{"newb":{"sumTotalChargeTaxExclusive":31637,"sumTotalChargeTaxInclusive":34800,"taxType":"exclusive"}}}},"rooms":{}}},"isCamby":false,"isDated":true,"isHotelFixed":true,"isNearbySearch":false,"isSecret":false,"isShowCrossSearch":true,"isSqueezingCambyFlag":false,"narrowingArea":[],"rtcond":{"f_sort":["hotel_kin_low"],"f_campaign":[""],"f_point_min":["0"],"f_gcode":[""],"f_cd":["03"],"f_dai":["japan"],"f_chu":["gunma"],"f_shou":["numata"],"f_sai":[""],"f_latitude":["0.0"],"f_longitude":["0.0"],"f_km":[""],"f_squeezes":[],"f_nen1":["2020"],"f_tuki1":["04"],"f_hi1":["01"],"f_nen2":["2020"],"f_tuki2":["04"],"f_hi2":["02"],"f_otona_su":["1"],"f_s1":["0"],"f_s2":["0"],"f_y1":["0"],"f_y2":["0"],"f_y3":["0"],"f_y4":["0"],"f_heya_su":["1"],"f_kin":[""],"f_kin2":["0"],"f_ido":["0.0"],"f_kdo":["0.0"],"f_teikei":[""],"f_disp_type":[""],"f_page":["1"],"f_hyoji":["30"],"f_image":["1"],"f_setubi":[""]},"rtcondex":{"dated":true,"f_tab":"hotel"},"totalResults":[1]};
料金は以下が税抜き価格として管理されていました。この部分を引っこ抜きます。
"sumTotalChargeTaxExclusive":18000
料金を自動取得するスクリプト
for j in `seq 1 30` do jj=`expr $j + 1` echo -n $j, curl https://search.travel.rakuten.co.jp/ds/vacant/searchVacant?f_chu=gunma\&f_shou=numata\&f_sai=\&f_hi1=$j\&f_tuki1=4\&f_nen1=2020\&f_hi2=$jj\&f_tuki2=4\&f_nen2=2020\&f_no=134873\&f_kin=\&f_kin2=0\&f_tab=plan\&f_sort=kin\&f_heya_su=1\&f_otona_su=1\&f_s1=0\&f_s2=0\&f_y1=0\&f_y2=0\&f_y3=0\&f_y4=0\&f_kaiin_no=\&f_kaiin_tel=\&f_jyoken=no\&f_cd=03\&f_dai=japan\&f_image=1\&f_page=1\&f_hyoji=30\&ref=info 2>/dev/null| grep sumTotalChargeTaxExclusive | awk '{print substr($0,index($0,"sumTotalChargeTaxExclusive")+28)}' | cut -d"," -f1 done
出力結果は以下です。
./rakuten_travel_test.sh 1,18000 2,18000 3,28000 4,5,19000 6,18000 7,18000 8,18000 9,18000 10,18000 11,12,18000 13,18000 14,18000 15,18000 16,18000 17,18000 18,19,18000 20,18000 21,18000 22,18000 23,18000 24,19000 25,26,18000 27,18000 28,18000 29,28000 30,19000
seq 1 30
とすることで4/1から4/30までの一か月分を出力してみました。
終わりに
今回は楽天APIを利用せずにサクッと実装してみました。ヒットしない場合に改行されないなどイケてない箇所もありますが、同様なことを実施したい方は是非参考ください。