如何在嵌套闭合Shadow Root中定位iframe以绕过Cloudflare人机验证
Cloudflare人机验证绕过:嵌套Shadow Root与IFrame访问问题
我使用Python、Selenium及JavaScript编写程序,尝试绕过Cloudflare的“Verify that you are human”人机验证。当前遇到的核心问题是:目标复选框位于一个iframe内,该iframe处于外层闭合Shadow Root中,且iframe内部还有一个闭合Shadow Root。我已成功进入外层Shadow Root,但无法访问其中的iframe。
现有代码
from time import sleep from selenium import webdriver from selenium.webdriver.common.by import By driver = webdriver.Chrome() # Inject script to force shadow DOMs open driver.execute_cdp_cmd('Page.addScriptToEvaluateOnNewDocument', {'source': """ Element.prototype._attachShadow = Element.prototype.attachShadow; Element.prototype.attachShadow = function () { return this._attachShadow( { mode: "open" } ); }; """}) # open the site driver.get("https://annas-archive.org/slow_download/c9cc2ebc974bb1955881807bdca7807d/0/0") # wait for the page to load properly sleep(3) # Access the outer shadow DOM outer_shadow_host = driver.find_element(By.CSS_SELECTOR, '#JStsl2 > div > div') outer_shadow_root = driver.execute_script('return arguments[0].shadowRoot', outer_shadow_host) # locate the iframe iframe = outer_shadow_root.find_element(By.CSS_SELECTOR, "#cf-chl-widget-xn7qb") # Switch to the iframe driver.switch_to.frame(iframe) # Access the inner shadow DOM inner_shadow_host = outer_shadow_root.find_element(By.CSS_SELECTOR, 'body') inner_shadow_root = driver.execute_script('return arguments[0].shadowRoot', inner_shadow_host) # Find and interact with the target element inside the inner shadow root target_element = inner_shadow_root.find_element(By.XPATH, '//input[type="checkbox"]') target_element.click()
已尝试的方法
- 使用
By.TAG_NAME和By.XPATH定位iframe - 执行脚本设置元素可见:
driver.execute_script("arguments[0].style.display='block'; arguments[0].style.visibility='visible';", iframe)
问题分析与修复方案
1. 核心问题点
- CDP脚本注入时机滞后:页面部分元素可能在脚本生效前已创建闭合Shadow Root,导致外层Shadow Root仍无法访问。
- 上下文切换错误:切换到iframe后,仍从外层Shadow Root查找内部元素,而非切换后的iframe上下文。
- 固定等待不稳定:
sleep(3)无法适配页面加载速度,易导致元素未加载完成就执行后续操作。
2. 修复后的代码
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 # 初始化Chrome配置,提前注入反检测脚本 options = webdriver.ChromeOptions() options.add_experimental_option("excludeSwitches", ["enable-automation"]) options.add_experimental_option('useAutomationExtension', False) driver = webdriver.Chrome(options=options) # 确保脚本在页面加载前执行,强制所有Shadow Root为open模式,并隐藏webdriver特征 driver.execute_cdp_cmd('Page.addScriptToEvaluateOnNewDocument', { 'source': """ Element.prototype._attachShadow = Element.prototype.attachShadow; Element.prototype.attachShadow = function () { return this._attachShadow({ mode: "open" }); }; Object.defineProperty(navigator, 'webdriver', { get: () => undefined }); """ }) # 打开目标页面 driver.get("https://annas-archive.org/slow_download/c9cc2ebc974bb1955881807bdca7807d/0/0") wait = WebDriverWait(driver, 10) # 等待外层Shadow Host加载完成并获取Shadow Root outer_shadow_host = wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, '#JStsl2 > div > div'))) outer_shadow_root = driver.execute_script('return arguments[0].shadowRoot', outer_shadow_host) # 在Shadow Root内等待iframe加载完成 iframe = wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, 'iframe[title*="Cloudflare Turnstile"]')), root=outer_shadow_root) # 切换到iframe上下文 driver.switch_to.frame(iframe) # 等待iframe内的Shadow Host加载并获取内部Shadow Root inner_shadow_host = wait.until(EC.presence_of_element_located((By.TAG_NAME, 'body'))) inner_shadow_root = driver.execute_script('return arguments[0].shadowRoot', inner_shadow_host) # 等待复选框可点击并执行点击操作 target_element = wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR, 'input[type="checkbox"]')), root=inner_shadow_root) target_element.click() # 后续若需操作主页面,切换回默认上下文 # driver.switch_to.default_content()
3. 关键优化说明
- 提前注入CDP脚本:确保页面所有Shadow Root在创建时即为open模式,同时隐藏
navigator.webdriver属性,降低Cloudflare检测概率。 - 动态选择器替换:用
iframe[title*="Cloudflare Turnstile"]替代动态生成的ID选择器,避免因ID变化导致定位失败。 - 显式等待替代固定睡眠:使用
WebDriverWait等待元素加载完成,提升代码稳定性。 - 上下文正确切换:切换到iframe后,在当前上下文查找内部元素,而非外层Shadow Root。
内容的提问来源于stack exchange,提问作者effendi
相关产品推荐
相关产品推荐

