使用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
相关产品推荐
相关产品推荐

