You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Selenium操作迪士尼预约页无法自动点击按钮问题咨询

问题根因

你初步排查的Shadow Root方向完全正确。这个迪士尼预约页的所有交互组件都基于Web Components封装,Theme Park Tickets、日期选择按钮都在多层嵌套的Shadow DOM内部,常规从文档根节点发起的XPath、ID、Name定位无法穿透Shadow DOM的封装边界,直接查找必然抛出元素不存在的报错,这就是之前所有定位尝试失败的核心原因。

解决方案

Selenium 4及以上版本原生支持Shadow Root节点操作,不需要注入额外JS,只要逐层获取每一层Shadow Root节点,在对应节点的上下文内查找下一级元素即可,不要直接从driver全局发起查找。

前置环境要求

  • Selenium版本≥4.0
  • ChromeDriver版本和本地安装的Chrome浏览器大版本完全匹配

可直接运行的修正代码

from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from time import sleep

def click_shadow_element(driver, root_selector, nested_selectors):
    """
    逐层穿透Shadow Root查找并点击目标元素
    :param driver: webdriver实例
    :param root_selector: 最外层非Shadow宿主元素的定位元组
    :param nested_selectors: 从第一层Shadow开始,每层宿主/目标元素的定位元组列表
    """
    current_node = WebDriverWait(driver, 15).until(
        EC.presence_of_element_located(root_selector)
    )
    # 逐层穿透Shadow边界
    for selector in nested_selectors[:-1]:
        shadow_root = current_node.shadow_root
        current_node = WebDriverWait(shadow_root, 10).until(
            EC.presence_of_element_located(selector)
        )
    # 定位最终目标按钮,等待可点击后触发点击
    target = WebDriverWait(current_node.shadow_root, 10).until(
        EC.element_to_be_clickable(nested_selectors[-1])
    )
    target.click()

def main():
    while True:
        options = Options()
        # 如需后台运行可打开下面的无头配置
        # options.add_argument("--headless=new")
        driver = webdriver.Chrome(options=options)
        try:
            driver.get('https://disneyworld.disney.go.com/availability-calendar/?segments=tickets,resort,passholder&defaultSegment=tickets')
            driver.maximize_window()
            sleep(7)

            # 第一步:点击Theme Park Tickets按钮
            click_shadow_element(
                driver,
                root_selector=(By.TAG_NAME, "app-root"),
                nested_selectors=[
                    (By.TAG_NAME, "aw-availability-selector"),
                    (By.TAG_NAME, "dprd-radio-group"),
                    (By.CSS_SELECTOR, "dprd-button:nth-child(1)"),
                    (By.CSS_SELECTOR, "button")
                ]
            )
            sleep(2)

            # 第二步:点击July 20日期按钮
            calendar_host = WebDriverWait(driver, 15).until(
                EC.presence_of_element_located((By.TAG_NAME, "aw-availability-calendar"))
            )
            calendar_shadow = calendar_host.shadow_root
            july20_btn = WebDriverWait(calendar_shadow, 10).until(
                EC.element_to_be_clickable((By.CSS_SELECTOR, "button[aria-label*='July 20']"))
            )
            july20_btn.click()
            sleep(3)

            # 后续检测Disney's Hollywood Studios对勾、发提醒邮件、判断是否循环的逻辑可在此处补充
            # 乐园选项同样在对应组件的Shadow Root内,按上述穿透逻辑查找即可

        except Exception as e:
            print(f"本次运行出错: {str(e)}")
        finally:
            driver.quit()
            # 刷新间隔建议不短于15秒,避免被站点反爬拦截
            sleep(30)

if __name__ == "__main__":
    main()

关键注意点

  • 不要使用从<html>标签开始的绝对XPath,这类路径层级太深,页面稍有迭代就会失效。Shadow DOM场景下优先用CSS选择器搭配稳定属性(比如组件标签名、aria-label、角色属性)定位,稳定性远高于XPath。
  • 不需要用click_and_hold做长按操作,普通按钮直接调用click()即可,长按反而会触发页面拖拽、文本选中之类的异常交互。
  • Shadow Root内的元素不能直接通过driver全局查找,必须先拿到对应元素的宿主节点,获取宿主的shadow_root属性后,在这个shadow_root上下文里查找内部元素,跨层查找必然失败。
  • 循环逻辑里必须在每次循环结束后调用driver.quit()销毁浏览器实例,否则会出现内存泄漏,运行不了几次程序就会因为内存占满崩溃。
  • 后续检测对勾标识时,找到对应Disney's Hollywood Studios选项节点后,判断勾选状态的class是否存在、或者勾选图标元素是否加载出来即可。

内容的提问来源于stack exchange,提问作者Samuel Staggs

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.27 03:15:40