楽天トラベルAPIの空き室検索を使って、好きな旅館を空き室検索するPythonプログラム、作りました。
楽天トラベルAPIを使うための準備
楽天トラベルAPIを利用するには、お持ちの楽天アカウント(無い人は作成)で
Rakuten Web Serviceにログインし、アプリIDを取得する必要がある。
ネットを探すと色々な人が解説しているのでご参照ください。
楽天トラベル空き室検索APIを使ってみる
まずは単純に以下の検索条件で空き室を検索してみる。
「ホテル番号」は、各ホテルに割り当てられた一意の番号。
楽天トラベルのホテルのTOPページに飛んでもらい、URLのこの部分↓を抜き出せばOK(楽天トラベル施設検索APIを使っても取得できるが、面倒くさいので…)
星野リゾート リゾナーレ小浜島<小浜島> 宿泊予約【楽天トラベル】 (rakuten.co.jp)
code
import requests
import json
import time
def search():
REQUEST_URL = "https://app.rakuten.co.jp/services/api/Travel/VacantHotelSearch/20170426"
APP_ID = "自分のアプリID"
hotelNum="178403"
checkinDate="2023-06-24"
checkoutDate="2023-06-25"
condition="kinen,breakfast"
params = {
"format":"json",
"applicationId":APP_ID,
"hotelNo":hotelNum,
"checkinDate":checkinDate,
"checkoutDate":checkoutDate,
"adultNum":2,
"squeezeCondition":condition,
"sort":"+roomCharge"
}
response = requests.get(REQUEST_URL, params)
time.sleep(1)
res = json.loads(response.text)
print(res)
if __name__ == '__main__':
search()
APP_ID = "自分のアプリID"
"自分のアプリID"の部分には、あらかじめ取得しておいた楽天APIのアプリIDを入れる。
実行結果
Oh.....ごちゃごちゃ(;´・ω・)
JSON形式でデータが返ってくるのだけれど、私の使っている開発環境(Jupyter Notebook)は整列してくれないので見づらい。
Notepad++を使ってJSONデータを整形してみると以下になった。
実行結果
{
'pagingInfo': {
'recordCount': 1,
'pageCount': 1,
'page': 1,
'first': 1,
'last': 1
},
'hotels': [{
'hotel': [{
'hotelBasicInfo': {
'hotelNo': 178403,
'hotelName': '星野リゾート\u3000リゾナーレ小浜島<小浜島>',
'hotelInformationUrl': 'https://img.travel.rakuten.co.jp/image/tr/api/re/pvonD/?f_no=178403',
'planListUrl': 'https://img.travel.rakuten.co.jp/image/tr/api/re/vFumt/?f_no=178403&f_flg=PLAN',
'dpPlanListUrl': 'https://img.travel.rakuten.co.jp/image/tr/api/re/WzozX/?noTomariHotel=178403',
'reviewUrl': 'https://img.travel.rakuten.co.jp/image/tr/api/re/gJNfM/?f_hotel_no=178403',
'hotelKanaName': 'ほしのりぞーと\u3000りぞなーれこはまじま',
'hotelSpecial': '石垣島から25分。世界有数の珊瑚の海が広がる、沖縄離島のプライベートビーチリゾート。',
'hotelMinCharge': 20000,
'latitude': 87583.57,
'longitude': 446393.82,
'postalCode': '907-1221',
'address1': '沖縄県',
'address2': '八重山郡竹富町小浜2954',
'telephoneNo': '050-3134-8093',
'faxNo': '000-000-0000',
'access': '石垣空港',
'parkingInformation': '有り\u300020台\u3000無料\u3000予約不要',
'nearestStation': '石垣空港',
'hotelImageUrl': 'https://img.travel.rakuten.co.jp/share/HOTEL/178403/178403.jpg',
'hotelThumbnailUrl': 'https://img.travel.rakuten.co.jp/HIMG/90/178403.jpg',
'roomImageUrl': 'https://img.travel.rakuten.co.jp/share/HOTEL/178403/178403_kan1.jpg',
'roomThumbnailUrl': 'https://img.travel.rakuten.co.jp/HIMG/INTERIOR/178403.jpg',
'hotelMapImageUrl': 'https://img.travel.rakuten.co.jp/share/HOTEL/178403/178403map.gif',
'reviewCount': 81,
'reviewAverage': 4.57,
'userReview': 'スタッフ全員の接客態度には非常に好感が持てて、さりげない語りかけとおもてなしは好印…\u30002023-05-17 01:17:15投稿 つづきはこちら'
}
}, {
'roomInfo': [{
'roomBasicInfo': {
'roomClass': 'ss4',
'roomName': 'スーペリアスイート',
'planId': 5566607,
'planName': '特別優待プラン<朝食付>',
'pointRate': 1,
'withDinnerFlag': 0,
'dinnerSelectFlag': 0,
'withBreakfastFlag': 1,
'breakfastSelectFlag': 0,
'payment': '2',
'reserveUrl': 'https://img.travel.rakuten.co.jp/image/tr/api/re/IdsCY/?f_no=178403&f_syu=ss4&f_hi1=2023-06-24&f_hi2=2023-06-25&f_heya_su=1&f_otona_su=2&f_s1=0&f_s2=0&f_y1=0&f_y2=0&f_y3=0&f_y4=0&f_camp_id=5566607',
'salesformFlag': 0
}
}, {
'dailyCharge': {
'stayDate': '2023-06-24',
'rakutenCharge': 39150,
'total': 78300,
'chargeFlag': 0
}
}
]
~~~~~~以下略~~~~~~
ちょっとは見やすくなったかな(^^;)
このJSONデータから、欲しい情報だけをピックアップするコードを追加する。
code
hotelName=res["hotels"][0]["hotel"][0]["hotelBasicInfo"]["hotelName"]
roomName=res["hotels"][0]["hotel"][1]["roomInfo"][0]["roomBasicInfo"]["roomName"]
planName=res["hotels"][0]["hotel"][1]["roomInfo"][0]["roomBasicInfo"]["planName"]
stayDate=res["hotels"][0]["hotel"][1]["roomInfo"][1]["dailyCharge"]["stayDate"]
totalCrg=res["hotels"][0]["hotel"][1]["roomInfo"][1]["dailyCharge"]["total"]
planUrl=res["hotels"][0]["hotel"][1]["roomInfo"][0]["roomBasicInfo"]["reserveUrl"]
allplanUrl=res["hotels"][0]["hotel"][0]["hotelBasicInfo"]["planListUrl"]
txt=""
txt = txt + '\r\n' \
+ "宿名: " + hotelName + '\r\n' \
+ "部屋名: " + roomName + '\r\n' \
+ "プラン名: " + planName + '\r\n' \
+ "宿泊日: " + stayDate + '\r\n' \
+ "価格: " + str(totalCrg) + "円" + '\r\n' \
+ "予約ページURL: " + planUrl + '\r\n' \
+ "プラン一覧URL: " + allplanUrl
print(txt)
実行結果
宿名: 星野リゾート リゾナーレ小浜島<小浜島>
部屋名: スーペリアスイート
プラン名: 特別優待プラン<朝食付>
宿泊日: 2023-06-24
価格: 78300円
予約ページURL: https://img.travel.rakuten.co.jp/image/tr/api/re/IdsCY/?f_no=178403&f_syu=ss4&f_hi1=2023-06-24&f_hi2=2023-06-25&f_heya_su=1&f_otona_su=2&f_s1=0&f_s2=0&f_y1=0&f_y2=0&f_y3=0&f_y4=0&f_camp_id=5566607
プラン一覧URL: https://img.travel.rakuten.co.jp/image/tr/api/re/vFumt/?f_no=178403&f_flg=PLAN
JSON形式のデータの見方は、初心者にはなかなか辛いものがあったけれど、なんとか抜き出せた。。。
最後に今日作ったソースコードと、スクレイピングの勉強に使用した書籍を貼り付けておきます。
code
import requests
import json
import time
def search():
REQUEST_URL = "https://app.rakuten.co.jp/services/api/Travel/VacantHotelSearch/20170426"
APP_ID = "自分のアプリID"
hotelNum="178403"
checkinDate="2023-06-24"
checkoutDate="2023-06-25"
condition="kinen,breakfast"
params = {
"format":"json",
"applicationId":APP_ID,
"hotelNo":hotelNum,
"checkinDate":checkinDate,
"checkoutDate":checkoutDate,
"adultNum":2,
"squeezeCondition":condition,
"sort":"+roomCharge"
}
response = requests.get(REQUEST_URL, params)
time.sleep(1)
res = json.loads(response.text)
hotelName=res["hotels"][0]["hotel"][0]["hotelBasicInfo"]["hotelName"]
roomName=res["hotels"][0]["hotel"][1]["roomInfo"][0]["roomBasicInfo"]["roomName"]
planName=res["hotels"][0]["hotel"][1]["roomInfo"][0]["roomBasicInfo"]["planName"]
stayDate=res["hotels"][0]["hotel"][1]["roomInfo"][1]["dailyCharge"]["stayDate"]
totalCrg=res["hotels"][0]["hotel"][1]["roomInfo"][1]["dailyCharge"]["total"]
planUrl=res["hotels"][0]["hotel"][1]["roomInfo"][0]["roomBasicInfo"]["reserveUrl"]
allplanUrl=res["hotels"][0]["hotel"][0]["hotelBasicInfo"]["planListUrl"]
txt=""
txt = txt + '\r\n' \
+ "宿名: " + hotelName + '\r\n' \
+ "部屋名: " + roomName + '\r\n' \
+ "プラン名: " + planName + '\r\n' \
+ "宿泊日: " + stayDate + '\r\n' \
+ "価格: " + str(totalCrg) + "円" + '\r\n' \
+ "予約ページURL: " + planUrl + '\r\n' \
+ "プラン一覧URL: " + allplanUrl
print(txt)
if __name__ == '__main__':
search()