Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

This article is a Private article. Only a writer and users who know the URL can access it.
Please change open range to public in publish setting if you want to share this article with other users.

More than 1 year has passed since last update.

キャンセル待ちのディズニーチケットを最速で獲得する方法

Posted at

はじめに

この時期のディズニーチケットって早めに売り切れますよね。正直キャンセル待ちのチケットを手動でゲットするのは、かなり大変です。自分も挑戦してみたのですが、ものの数秒で他の人に取られてしまい購入できませんでした。
しかし幸運なことに現状チケットを獲得する方法は、ひたすら画面に向き合い、何時間も手動でクリックを行うしかないようです。(下記システムは現在おそらく使用できない?)

エンジニアたる我々はそんな馬鹿げたことをせず、自動化しましょう。
本記事はスクレイピングの技術を用いて、キャンセル待ちのディズニーチケット争奪戦で優勝しようというお話です。

注意事項

スクレイピング技術は一歩間違えるとDoS攻撃と認定される可能性があるため慎重に行うようにしてください。実際に15秒に1回自動クリックするツールが公開されており、Xでプチ炎上していました。
(参考:https://x.com/satorunet/status/1453376865423429637?s=20

1秒に何回アクセスすればDoS攻撃になるというしっかりとした定義が決まっているわけではありません。アクセスしているユーザ数やサーバーの強度など様々な変数があるため一概に定義できないのです。実際、1秒に平均1回のアクセスで岡崎市立中央図書館のサイトを落としてしまい、その結果逮捕された事件があります。
(参考:https://x.gd/dsEI3

私のコードですと5〜8秒(人がアクセスしている風を装うために乱数で設定しています)に1回アクセスするようなシステムなのでDoS攻撃だと認定されることはないと思われますが、上記のXのポストでプチ炎上している経緯もあり、本記事は限定公開にします。ソースコードもprivateにしました。

結論

ChromeDriverとSeleniumを用いて、指定した日付と人数分のディズニーチケットを最速でカートに入れ、LINEに通知を送るシステムを作成しました。
これにより、キャンセル待ちのディズニーチケット争奪戦に優勝することができました。

作成方法

  1. ChromeDriverのダウンロード
  2. ディズニーサイトへの自動ログイン
  3. ディズニーチケット状況のチェック
  4. LINEに通知を送る

の4点に分けてそれぞれ解説していこうと思います。

1. ChromeDriverのダウンロード

ChromeDriverとは、Google Chromeをプログラムで自動化を実現してくれるツールです。
1つ注意点として、このChromeDriverはお使いのGoogle Chromeに適したバージョンをダウンロードする必要があります。
バージョン114以前のダウンロードはこちらから行います。しかし、現在私が使用しているGoogle Chromeのバージョンが120だったため、こちらを参考にしてダウンロードしました。

続いてコードの説明です。Chromeドライバーの初期化ではダウンロードしたChromeDriverの絶対パスを指定してあげる必要があります。また、Chromeを起動ではChromeの絶対パスとプロフィール名が必要です。この2つに関してはchrome://version/プロフィール パスから確認することができます。

# Chromeドライバーの初期化
driver_path = "/path/to/your/chromedriver"
service = Service(executable_path=driver_path)
# Chromeを起動
options = Options()
options.add_argument("--user-data-dir=/path/to/your/Chrome")
options.add_argument("--profile-directory=your_profile_name")
driver = webdriver.Chrome(service=service, options=options)

2. ディズニーサイトへの自動ログイン

ディズニーサイトではチケットをカートに入れる際、ログインしている状態が必要だったため、Chromeの立ち上げの際にログインするようにしました。

ログインするためには

  1. メールアドレスの入力
  2. 続けるボタンクリック
  3. パスワードの入力
  4. ログインボタンクリック

の4フェーズがあるため、5秒ほどロスが発生します。そのため、最初にログインしている状態を作る必要性があります。

まず、上画像よりメニューボタンから同意してログイン/新規登録ボタンをクリックする必要があります。
そのために以下のコードを使用してクリックさせます。

# "同意してログイン/新規登録" ボタンをクリック
login_button = WebDriverWait(driver, 10).until(
    EC.element_to_be_clickable((By.CSS_SELECTOR, "a.m-btnType1.c-login"))
)
login_button.click()

上記のコードでは、要素(今回はボタン)が表示かつクリック可能な状態になるまで待機し、click()でクリックを行うというものです。
a.m-btnType1.c-loginというのは下画像のようにHTMLで同意してログイン/新規登録を指す名称です。こちらはChromeのディベロッパーツールで詳しく確認することができます。

基本的に上記のコードのように各要素が表示されかつクリックや入力ができる状態になるまで待機して、各動作を行うといった感じです。
実際のログインについてもコード内でパラメータ化しているメールアドレスとパスワードを入力画面に自動で打ち込まれるようにしてあります。

3. ディズニーチケット状況のチェック

今回はディズニーランドに限定して指定した日付のチケット状況をチェックします。パークの指定についても前述のコードのようにディズニーランドボタンを指定してクリックさせます。

# 東京ディズニーランドのボタンをクリック
tdl_button = WebDriverWait(driver, 10).until(
    EC.element_to_be_clickable((By.ID, "park_select_tdl"))
)
tdl_button.click()

現在(2023/12/18)の状況です。ここで、カレンダーには◯ △ ✕の3種類あることが下画像から確認できます。

ディベロッパーツールで確認してみると◯ △is-OKで、is-NGという形で区別されてました。

ここで1つ豆知識なのですが、ディズニーのシステム上、自分のカートにチケットを入れることが出来れば他の人に取られない仕様になっています。なので、他の人より速く自分のカートに入れることが出来れば購入できたようなものです。

最終的に、指定した日付にis-OKがある場合、チケットをカートに入れ、LINEに通知を送るシステムにしました。

# 指定した日付のチケット情報を取得する等
ticket_info = driver.find_element(By.CSS_SELECTOR, f"td[data-date='{date_to_check}']")

# "is-OK" クラスがあるかチェック
if "is-OK" in ticket_info.get_attribute("class"):
    ## チケットをカートに入れてLINEに通知を送る処理

チケットをカートに入れるまでの処理はパークチケットの券種とその枚数、購入確認用のチェックがあります。手動でやると5秒くらいかかりますが自分のシステムだと1秒かかりません。

4. LINEに通知を送る

LINE Chat Botを作成し、チケットをカートに入れた際に自分のLINEアカウントに通知を送るようにしたい。これについては記事がありふれているため、あまり解説しません。

まずLINE Developersに登録を行い、チャネルを作成してください。そしてLINEアカウントのユーザーIDとチャネルアクセストークンを取得します。これはMessaging APIを使用して自分のLINEアカウントにメッセージを送信するときに使用します。
コードは以下のようになっており、これを使用することで作成したLINE Chat Botから自分のLINEアカウントへ通知を送ることができます。

def send_line_notification(message, access_token, userID):
    headers = {
        "Authorization": f"Bearer {access_token}",
        "Content-Type": "application/json"
    }
    data = {
        "to": userID,
        "messages": [{"type": "text", "text": message}]
    }
    response = requests.post("https://api.line.me/v2/bot/message/push", headers=headers, json=data)

結果

無事ディズニーチケットを自動でカートに入れることができました。
自分は今回初めてスクレイピングの勉強したのですが、結構面白かったです。
是非皆様も楽しいスクレイピングライフを。

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

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?