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

使用Selenium和Python访问多层ShadowRoot嵌套HTML的方法及Wordle解谜机器人页面HTML获取问题

嘿,针对你的两个问题,我来给你详细解答:

1. 如何使用Selenium和Python访问多层ShadowRoot嵌套的HTML内容?

Shadow DOM是浏览器用来封装组件内部结构的机制,普通的Selenium元素查找方法没法直接穿透ShadowRoot,得逐层获取才行。具体步骤如下:

  • 先找到包含ShadowRoot的宿主元素(就是带有shadow-root标记的元素的父元素)
  • 通过宿主元素的.shadow_root属性获取ShadowRoot对象
  • 如果还有嵌套的ShadowRoot,重复上面两步,逐层深入

举个多层嵌套的例子,假设页面结构是这样的:

<div id="outer-host">
  #shadow-root
    <div id="inner-host">
      #shadow-root
        <p id="target-text">我是嵌套在两层ShadowRoot里的内容</p>
    </div>
</div>

对应的Python代码实现:

from selenium import webdriver
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By

driver = webdriver.Chrome()
driver.get("你的目标页面URL")

# 第一步:等待外层ShadowRoot的宿主元素加载完成
outer_host = WebDriverWait(driver, 10).until(
    EC.presence_of_element_located((By.ID, "outer-host"))
)
# 获取外层ShadowRoot
outer_shadow = outer_host.shadow_root

# 第二步:在外层ShadowRoot内找到内层宿主元素
inner_host = outer_shadow.find_element(By.ID, "inner-host")
# 获取内层ShadowRoot
inner_shadow = inner_host.shadow_root

# 现在就能访问最内层的目标元素了
target_text = inner_shadow.find_element(By.ID, "target-text").text
print(target_text)

如果嵌套层数更多,就按这个逻辑继续逐层获取就行。另外,也可以用JavaScript执行来直接获取,写法更简洁:

target_text = driver.execute_script("""
  return document.querySelector('#outer-host')
    .shadowRoot.querySelector('#inner-host')
    .shadowRoot.querySelector('#target-text').textContent;
""")
2. Wordle机器人获取完整HTML的问题

你遇到的核心问题其实也是Shadow DOM导致的——Wordle的游戏界面完全封装在ShadowRoot里面,直接获取body的innerHTML肯定拿不到游戏相关内容,因为那些内容都藏在ShadowRoot内部。

我帮你调整了代码,同时优化了一些细节(比如用等待替代time.sleep,更可靠):

from selenium.common.exceptions import NoSuchElementException, TimeoutException, ElementClickInterceptedException
from selenium.webdriver.common.keys import Keys
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
import time

# 初始化Chrome浏览器(现在ChromeDriver无需指定executable_path,只要版本匹配即可)
chrome_options = webdriver.ChromeOptions()
driver = webdriver.Chrome(options=chrome_options)
driver.get("https://www.powerlanguage.co.uk/wordle/")

wait = WebDriverWait(driver, 10)
try:
    # 先尝试关闭初始弹窗(如果有的话)
    close_btn = wait.until(EC.element_to_be_clickable((By.CLASS_NAME, "Modal-module_closeBtn__b4z74")))
    close_btn.click()
except TimeoutException:
    # 没有弹窗就点击body激活输入区域
    body = wait.until(EC.presence_of_element_located((By.TAG_NAME, "body")))
    body.click()

# 输入猜测单词并提交
body.send_keys("adieu")
body.send_keys(Keys.ENTER)

# 等待结果加载(这里可以换成等待行元素状态变化的更精准等待)
time.sleep(2)

# 找到Wordle游戏的核心宿主元素<game-app>,它包含了整个游戏的ShadowRoot
game_app = wait.until(EC.presence_of_element_located((By.TAG_NAME, "game-app")))
game_shadow = game_app.shadow_root

# 现在可以获取游戏内的完整内容了,比如遍历每一行的字母状态
game_rows = game_shadow.find_elements(By.TAG_NAME, "game-row")
for row in game_rows:
    # game-row本身也有ShadowRoot,需要继续获取
    row_shadow = row.shadow_root
    tiles = row_shadow.find_elements(By.TAG_NAME, "game-tile")
    for tile in tiles:
        letter = tile.get_attribute("letter")
        status = tile.get_attribute("evaluation")
        print(f"字母: {letter}, 状态: {status}")  # status取值:correct(正确)、present(存在但位置错)、absent(不存在)

# 如果要获取整个游戏区域的innerHTML,执行这行即可
game_inner_html = game_shadow.get_attribute('innerHTML')
print(game_inner_html)

为什么之前的body.get_attribute('innerHTML')没用?因为game-app的内容是在它的ShadowRoot里,不属于body的直接DOM结构。浏览器开发者工具会自动展开ShadowRoot内容展示给你,但Selenium默认不会穿透,必须手动获取ShadowRoot才能访问里面的元素和HTML。

内容的提问来源于stack exchange,提问作者amc-man

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.28 10:17:31