🦄

6. 万博自動化検証 ― ページ遷移に沿った処理フロー(3日前空き枠先着予約 前編)

に公開

6. 万博自動化検証 ― 3日前空き枠先着予約 前編

📌 前回の記事5. 万博自動化検証 ― ページ遷移に沿った処理フロー(来場日変更編)


実行 URL(@match)


[https://ticket.expo2025.or.jp/event_search/?id=XXXX&keyword=&](https://ticket.expo2025.or.jp/event_search/?id=XXXX&keyword=&)*

※XXXXは実際の 自身のチケットID。


具体実装処理概要

1. パビリオン一覧の読み込み

  • ページには「もっと見る」ボタンがあり、押すごとに新しいパビリオン情報が読み込まれます。
  • この「もっと見る」押下を自動化することで、全件を展開して検索可能な状態にします。
  • ローディング中は待機し、消えたら次を押す処理を繰り返します。

2. 空き枠の検出と自動選択

  • 読み込まれたパビリオンのボタンを監視し、空き枠があるものを判定します。
  • 判定条件は以下のように設定:
    • 「空き枠あり」のアイコンが表示されている。
    • キーワードフィルタで対象ワードを含む/除外ワードを含まない。
  • 条件を満たしたら自動でクリックし、選択を進めます。

3. ログ・履歴管理

  • クリック成功時は履歴を localStorage に保存し、右下に簡易 UI を表示。
  • 履歴にはパビリオン名とクリック時刻を残し、リロード後も確認できます。
  • 外部通知(例:Discord Webhook)は省略しましたが、必要に応じて補足可能です。

サンプルコード

// ==UserScript==
// @name         万博自動化検証 - 3日前空き枠先着
// @namespace    http://tampermonkey.net/
// @version      1.0
// @match        https://ticket.expo2025.or.jp/event_search/?id=XXXX&keyword=&*
// @grant        none
// ==/UserScript==

(function() {
  'use strict';

  // --- 「もっと見る」ボタンのクリック ---
  function clickMore() {
    const moreBtn = document.querySelector("span.more-button"); // セレクタは省略
    if (moreBtn && isClickable(moreBtn)) {
      console.log("『もっと見る』をクリック");
      moreBtn.click();
      return true;
    }
    return false;
  }

  function isClickable(el) {
    if (!el) return false;
    const style = window.getComputedStyle(el);
    return !(style.display === "none" || style.visibility === "hidden" || el.getAttribute("aria-disabled") === "true");
  }

  // --- ローディング完了を待機 ---
  function waitForLoaderGone(callback) {
    const interval = setInterval(() => {
      const loader = document.querySelector(".loader"); // セレクタは省略
      if (!loader) {
        clearInterval(interval);
        callback();
      }
    }, 500);
  }

  // --- 空き枠が出たらクリック ---
  function tryClickAvailable() {
    const buttons = document.querySelectorAll("button.pavilion"); // セレクタは省略
    for (const btn of buttons) {
      if (btn.dataset.clicked) continue;

      const label = btn.textContent.trim();

      // キーワード条件(例: include / exclude)※詳細は省略
      const includeOk = true; // 実装時に条件を補う
      const excludeNg = false;

      if (includeOk && !excludeNg) {
        console.log("利用可能なパビリオンをクリック:", label);
        btn.click();
        btn.dataset.clicked = "true";

        addClickHistory(label);
        return true;
      }
    }
    return false;
  }

  // --- 履歴管理 ---
  const clickHistory = JSON.parse(localStorage.getItem("clickHistory") || "[]");

  function addClickHistory(name) {
    const now = new Date();
    const time = `${now.getHours()}:${now.getMinutes()}:${now.getSeconds()}`;
    clickHistory.unshift({ name, time });
    if (clickHistory.length > 10) clickHistory.pop();

    localStorage.setItem("clickHistory", JSON.stringify(clickHistory));
    updateHistoryDOM();
  }

  function updateHistoryDOM() {
    let el = document.getElementById("historyPanel");
    if (!el) {
      el = document.createElement("div");
      el.id = "historyPanel";
      el.style.position = "fixed";
      el.style.bottom = "10px";
      el.style.right = "10px";
      el.style.background = "rgba(0,0,0,0.7)";
      el.style.color = "#fff";
      el.style.padding = "10px";
      el.style.zIndex = "9999";
      document.body.appendChild(el);
    }
    el.innerHTML = "<b>クリック履歴:</b><br>" +
      clickHistory.map((h,i)=> `${i+1}. ${h.name} [${h.time}]`).join("<br>");
  }

  // --- 初期実行 ---
  clickMore();
  tryClickAvailable();

  // --- DOM変化を監視 ---
  const observer = new MutationObserver(() => {
    tryClickAvailable();
  });
  observer.observe(document.body, { childList: true, subtree: true });
})();

補足

  • 上記コードではセレクタ名(.loader, button.pavilion など)や外部通知の処理は省略しています。
    → 実装時には実際の DOM 構造や通知サービスに合わせて補う必要があります。
  • 「もっと見る」クリックとローディング待機を組み合わせることで、安定して全件を展開できます。
  • クリック履歴を UI 表示することで「どのパビリオンに入ったか」がすぐに確認できます。

免責事項

本記事は Web 自動化の学習記録をまとめたものであり、Expo 2025 チケット予約システムの不正利用を助長する意図は一切ありません。
実際にスクリプトを利用する場合は、万博公式の規定や利用規約に従うことが必須です。
本記事を参考にしたことによって生じたいかなる不利益・損害についても、筆者は責任を負いません。


Discussion