すやすや生活日記

専業主婦が日々を記録するブログ

【Python】楽天トラベルAPIで空き室検索 ~2~

 

前回のブログでは、楽天APIで好きなお宿の空き室検索をするPythonプログラムを作った。

popololo-nyanya.hatenablog.com

 

今回はそれを発展させ、

3か月先まで、土日の空き室を自動検索できるようにしたい。

 

日付の抽出

datetimeモジュールのtimedeltaオブジェクトを使って、日付の差を表すことができる。

例えば、72時間、3週間を引数にして実行してみると、それぞれ3日、21日という計算結果が出る。

<code>

day_A = datetime.timedelta(hours=72).days
print(day_A)

day_B = datetime.timedelta(weeks=3).days
print(day_B)

<結果>

3
21

これを使って、3か月先までの日付を出してみる。

timedeltaオブジェクトの引数にmonthはないので、1か月4.5週間として3か月を13週間として計算。

<code>

today = datetime.date.today() #今日の日付
days = datetime.timedelta(weeks=13).days #3か月先までの日数

for i in range(0, days): # 13週先まで、1日ずつカウントアップ
    print(today + datetime.timedelta(i))

<結果>

2023-06-16
2023-06-17
2023-06-18
.....
.....(中略)
.....
2023-09-12
2023-09-13
2023-09-14

 

次に、チェックイン日である土曜日だけを抽出してみる。

weekdayメソッドは、月曜日を 0、日曜日を 6 として、曜日を整数で返す。

<code>

day_C = datetime.date(2023, 11, 11).weekday() 
print(day_C)

<結果>

5

今年のいい夫婦の日(11月11日)は水曜日だそうです。

これを利用して、土曜日だけを抽出。

<code>

today = datetime.date.today() #今日の日付
days = datetime.timedelta(weeks=13).days #3か月先までの日数

for i in range(0, days): # 13週先まで、1日ずつカウントアップ
    if (today + datetime.timedelta(i)).weekday() == 5:
        print(today + datetime.timedelta(i))

<結果>

2023-06-17
2023-06-24
2023-07-01
2023-07-08
2023-07-15
2023-07-22
2023-07-29
2023-08-05
2023-08-12
2023-08-19
2023-08-26
2023-09-02
2023-09-09

 

楽天トラベルAPIで空き室検索

あとは前回のブログのソースコードと合体させるだけ。

<code>

import requests
import json
import time
import datetime

def search():
    # 13週(約3か月)先までの日数を数える
    today = datetime.date.today()
    days = datetime.timedelta(weeks=13).days

    #  スクレイピングで空き室検索
    for i in range(0, days): # 13週先まで、1日ずつカウントアップ
        if (today + datetime.timedelta(i)).weekday() == 5: #土曜日だったら宿検索する
            checkinDate = str(today + datetime.timedelta(i)) #チェックイン日
            checkoutDate = str(today + datetime.timedelta(i) + datetime.timedelta(1)) #チェックアウト日

            REQUEST_URL = "https://app.rakuten.co.jp/services/api/Travel/VacantHotelSearch/20170426"
            APP_ID = "自分のアプリID"
            hotelNum="178403"
            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)
            time.sleep(2)

if __name__=='__main__':
    search()

<結果>

35             res = json.loads(response.text)
     36 
---> 37             hotelName=res["hotels"][0]["hotel"][0]["hotelBasicInfo"]["hotelName"]
     38             roomName=res["hotels"][0]["hotel"][1]["roomInfo"][0]["roomBasicInfo"]["roomName"]
     39             planName=res["hotels"][0]["hotel"][1]["roomInfo"][0]["roomBasicInfo"]["planName"]

KeyError: 'hotels'

途中まで検索できていたのですが、エラー発生。

どうやら、空き室がないときに以下のJSONデータが返ってくるので、"hotels"なんてどこにも無いよ!と怒られている様子。

    {
      "error_description": "Data Not Found",
      "error": "not_found"
    }

空き室が無かった場合を考えてif文を追加。

<code>

import requests
import json
import time
import datetime

def search():
    # 13週(約3か月)先までの日数を数える
    today = datetime.date.today()
    days = datetime.timedelta(weeks=13).days

    #  スクレイピングで空き室検索
    for i in range(0, days): # 13週先まで、1日ずつカウントアップ
        if (today + datetime.timedelta(i)).weekday() == 5: #土曜日だったら宿検索する
            checkinDate = str(today + datetime.timedelta(i)) #チェックイン日
            checkoutDate = str(today + datetime.timedelta(i) + datetime.timedelta(1)) #チェックアウト日

            REQUEST_URL = "https://app.rakuten.co.jp/services/api/Travel/VacantHotelSearch/20170426"
            APP_ID = "自分のアプリID"
            hotelNum="178403"
            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)
            
            if "error_description" in res.keys(): # 空き室がないとき
                pass
            else:
                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)
            time.sleep(2)

if __name__=='__main__':
    search()

<結果>

宿名: 星野リゾート リゾナーレ小浜島<小浜島>
部屋名: スーペリアスイート
プラン名: 特別優待プラン<朝食付>
宿泊日: 2023-06-17
価格: 78300円
予約ページURL: https://img.travel.rakuten.co.jp/image/tr/api/re/IdsCY/?f_no=178403&f_syu=ss4&f_hi1=2023-06-17&f_hi2=2023-06-18&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
.....
.....(中略)
.....
宿名: 星野リゾート リゾナーレ小浜島<小浜島>
部屋名: スーペリアスイート
プラン名: 特別優待プラン<朝食付>
宿泊日: 2023-09-09
価格: 69300円
予約ページURL: https://img.travel.rakuten.co.jp/image/tr/api/re/IdsCY/?f_no=178403&f_syu=ss4&f_hi1=2023-09-09&f_hi2=2023-09-10&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

 

3か月先までの空き室情報が取得できました(^▽^)