1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

[Python]seleniumでdisney予約サイト自動操作

Posted at

内容

部屋名、日付を選択すればディズニーランドホテルの予約画面まで遷移

動機

ブラウザ操作やスクレイピングに慣れたいと思っていて、せっかくするなら興味があったディズニー予約サイトでやってみようと考えた。
ディズニー予約サイトではpythonのrequestsが使えなかったため、seleniumでブラウザ操作を再現する必要があることがわかり、seleniumに慣れる良い機会だと考えた。

環境

python 3.XX
selenium
chromedriver
以上をダウンロード

部屋選択・日付入力

実際はディズニーランドホテルだけで49種類もの部屋の種類がありましたが、見やすさのため省略しています。

# 事前に部屋選択を行う処理

# 部屋の種類リスト
# 見やすさの為、一部部屋のみ
room_types = [
    "スタンダード スーペリアルーム(1-3階)",
    "スタンダード スーペリアルーム(3-4階)",
    "スタンダード スーペリアルーム(4-9階)",
    "スタンダード スーペリアルーム(パークビュー)(3-6階)",
    "スタンダード スーペリアルーム(パークビュー)(7-8階)",
]

print("選択可能な部屋の種類:")
for idx, room in enumerate(room_types):
    print(f"{idx+1}: {room}")
room_choice = int(input("選択する部屋の種類の番号を入力してください: "))
selected_room_type = room_types[room_choice - 1]
print(f"\n選択された部屋の種類: {selected_room_type}")

# 予約希望日(YYYYMMDD形式)を入力。

# 希望日から対象の月を算出。
desired_date = input("予約希望日(例: 20250508)を入力してください: ").strip()
try:
    desired_datetime = datetime.datetime.strptime(desired_date, "%Y%m%d")
except Exception as e:
    print(f"日付形式が正しくありません: {str(e)}")
    sys.exit()

# 希望日から対象の月(例:"2025,5")を算出(後々必要)
selected_value = f"{desired_datetime.year},{desired_datetime.month}"
print(f"算出された対象月: {selected_value}")

実行すると

選択可能な部屋の種類:
1: スタンダード スーペリアルーム(1-3階)
2: スタンダード スーペリアルーム(3-4階)
3: スタンダード スーペリアルーム(4-9階)
4: スタンダード スーペリアルーム(パークビュー)(3-6階)
5: スタンダード スーペリアルーム(パークビュー)(7-8階)
選択する部屋の種類の番号を入力してください: 2

選択された部屋の種類: スタンダード スーペリアルーム(3-4階)
予約希望日(例: 20250508)を入力してください: 20250511
算出された対象月: 2025,5

ブラウザ操作

seleniumのversionによってはchromeのパスを通す必要があるそうです。
具体的にはselenium4.6以降の場合webdriver-managerのおかげでパスを通す必要がないらしいです。

# 以下、ChromeDriverを起動して自動操作を実施する

url = "https://reserve.tokyodisneyresort.jp/sp/hotel/search/"
chrome_options = Options()
#chrome_options.add_argument('--headless')   # ヘッドレスモードを有効にする場合はコメント解除
chrome_options.add_argument('--no-sandbox')
chrome_options.add_argument('--user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36')
chrome_options.add_argument('--disable-blink-features=AutomationControlled')
chrome_options.add_experimental_option('detach', True)

driver = webdriver.Chrome(options=chrome_options)

try:
    # トップページを表示
    driver.get(url)
    time.sleep(3)  # ページロード待機

    # 「ホテルから」をクリック
    link = WebDriverWait(driver, 10).until(
        EC.element_to_be_clickable((By.XPATH, "//*[text()='ホテルから']"))
    )
    link.click()

    # 「ホテル」をクリック(例として「東京ディズニーランド」を選択)
    link = WebDriverWait(driver, 10).until(
        EC.visibility_of_element_located((By.XPATH, "//a[contains(., '東京ディズニーランド')]"))
    )
    link.click()

    # XPath を動的に組み立てる(部屋の種類に合わせる)
    room_xpath = (
        f"//button[contains(@class, 'js-callVacancyStatusSearch') and "
        f"contains(@class, '{selected_room_type}')]"
    )
    print("使用する XPath:", room_xpath)
    room_button = WebDriverWait(driver, 10).until(
        EC.element_to_be_clickable((By.XPATH, room_xpath))
    )
    driver.execute_script("arguments[0].scrollIntoView(true);", room_button)
    try:
        room_button.click()
    except Exception:
        ActionChains(driver).move_to_element(room_button).click().perform()

    # 大人の人数を選択(例:2名)
    select_element = WebDriverWait(driver, 10).until(
        EC.element_to_be_clickable((By.ID, "adultNum"))
    )
    select_element.click()
    option = WebDriverWait(driver, 10).until(
        EC.element_to_be_clickable((By.XPATH, "//select[@id='adultNum']/option[@value='2']"))
    )
    option.click()

    # 「次へ」ボタンをクリック
    next_button = WebDriverWait(driver, 10).until(
        EC.element_to_be_clickable((By.CSS_SELECTOR, "button.next.js-conditionHide"))
    )
    next_button.click()

    # カレンダーのセレクトボックス(ID: boxCalendarSelect)から、算出された対象月をセット
    select_element = WebDriverWait(driver, 10).until(
        EC.presence_of_element_located((By.ID, "boxCalendarSelect"))
    )
    select_box = Select(select_element)
    select_box.select_by_value(selected_value)
    time.sleep(3)  # カレンダー更新待機

    # 希望日のセルを取得してクリック(data-date属性が一致し、かつ"ok"クラス付き)
    date_cell_xpath = f"//td[contains(@class, 'ok') and @data-date='{desired_date}']"
    try:
        date_cell = WebDriverWait(driver, 10).until(
            EC.element_to_be_clickable((By.XPATH, date_cell_xpath))
        )
        print(f"{desired_date} は空室があるようです。セルをクリックして詳細画面へ移行します。")
        date_cell.click()
    except Exception as e:
        print(f"{desired_date} のセルが見つからないか、クリックできませんでした: {str(e)}")
        driver.quit()
        sys.exit()
    
    # 詳細画面(予約手続きボタンが含まれる部分)の表示状態を変更
    room_detail_id = f"room_{desired_date}"
    
    driver.execute_script("document.getElementById('priceInformationList').style.display = 'block';")
    room_detail = WebDriverWait(driver, 10).until(
        EC.visibility_of_element_located((By.ID, room_detail_id))
    )
    # 「予約手続きに進む」ボタンを取得しクリック(テキストに「予約手続きに進む」を含み、disableクラスがないもの)
    try:
        reserve_button = WebDriverWait(driver, 10).until(
            EC.element_to_be_clickable((
                By.XPATH, f"//li[starts-with(@id, 'room_{desired_date}')]" +
                "//p[@class='btnReserve']/button[contains(., '予約手続きに進む') and not(contains(@class, 'disable'))]"
            ))
        )
        print("予約手続きに進むボタンが見つかりました。クリックします。")
        reserve_button.click()
    except Exception as e:
        print(f"予約手続きに進むボタンが見つからない、またはクリックできませんでした: {str(e)}")

except Exception as e:
    print(f"Error: {str(e)}")

finally:
    print('exit')

実行すると

使用する XPath: //button[contains(@class, 'js-callVacancyStatusSearch') and contains(@class, 'スタンダード スーペリアルーム(3-4階)')]
20250511 は空室があるようです。セルをクリックして詳細画面へ移行します。
予約手続きに進むボタンが見つかりました。クリックします。
exit

実際に予約を自動化する場合はサイト混雑時の待機部屋対策やページ遷移時の待機時間調整も必要です。サーバーへの負荷を考えての運用も必要ですね。

何かあればご教授ください🙇

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?