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

如何在嵌套闭合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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.17 14:07:36