如何在Shadow Root中点击按钮?Selenium报错解决方案
解决Selenium点击Shadow Root内按钮的InvalidArgumentException错误
问题场景
尝试用Selenium点击网页Shadow Root中的同意广告按钮,代码如下:
from selenium import webdriver from selenium.webdriver.chrome.options import Options from selenium.webdriver.chrome.service import Service from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.common.by import By import time print(f"Checking Browser driver...") options = Options() # options.add_argument('--headless=new') options.add_argument("start-maximized") options.add_argument('--log-level=3') options.add_experimental_option("prefs", {"profile.default_content_setting_values.notifications": 1}) options.add_experimental_option("excludeSwitches", ["enable-automation"]) options.add_experimental_option('excludeSwitches', ['enable-logging']) options.add_experimental_option('useAutomationExtension', False) options.add_argument('--disable-blink-features=AutomationControlled') srv=Service() driver = webdriver.Chrome (service=srv, options=options) waitWD = WebDriverWait (driver, 10) link = "https://www.firmy.cz/kraj-liberecky/liberec/1818-liberec?q=" driver.get (link) time.sleep(5) shadowHost = driver.find_element(By.XPATH,'//div[@class="szn-cmp-dialog-container"]') shadowRoot = shadowHost.shadow_root time.sleep(5) shadowRoot.find_element(By.XPATH, '//button[@data-testid="cw-button-agree-with-ads"]').click() input("Press!")
运行后抛出错误:
(selenium) C:\DEVNEU\Fiverr2025\TRY\readingmadness>python test.py Checking Browser driver... Traceback (most recent call last): File "C:\DEVNEU\Fiverr2025\TRY\readingmadness\test.py", line 29, in <module> shadowRoot.find_element(By.XPATH, '//button[@data-testid="cw-button-agree-with-ads"]').click() ~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "C:\DEVNEU\.venv\selenium\Lib\site-packages\selenium\webdriver\remote\shadowroot.py", line 53, in find_element return self._execute(Command.FIND_ELEMENT_FROM_SHADOW_ROOT, {"using": by, "value": value})["value"] ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "C:\DEVNEU\.venv\selenium\Lib\site-packages\selenium\webdriver\remote\shadowroot.py", line 82, in _execute return self.session.execute(command, params) ~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^ File "C:\DEVNEU\.venv\selenium\Lib\site-packages\selenium\webdriver\remote\webdriver.py", line 384, in execute self.error_handler.check_response(response) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^ File "C:\DEVNEU\.venv\selenium\Lib\site-packages\selenium\webdriver\remote\errorhandler.py", line 232, in check_response raise exception_class(message, screen, stacktrace) selenium.common.exceptions.InvalidArgumentException: Message: invalid argument: invalid locator (Session info: chrome=133.0.6943.60) Stacktrace: GetHandleVerifier [0x00007FF64EE46F15+28773] (No symbol) [0x00007FF64EDB2600] (No symbol) [0x00007FF64EC48FAA] (No symbol) [0x00007FF64EC9F05A] (No symbol) [0x00007FF64EC9F4FC] (No symbol) [0x00007FF64EC91CAC] (No symbol) [0x00007FF64ECC728F] (No symbol) [0x00007FF64EC91B36] (No symbol) [0x00007FF64ECC7460] (No symbol) [0x00007FF64ECEF6F3] (No symbol) [0x00007FF64ECC7023] (No symbol) [0x00007FF64EC8FF5E] (No symbol) [0x00007FF64EC911E3] GetHandleVerifier [0x00007FF64F19425D+3490733] GetHandleVerifier [0x00007FF64F1ABA43+3586963] GetHandleVerifier [0x00007FF64F1A147D+3544525] GetHandleVerifier [0x00007FF64EF0C9DA+838442] (No symbol) [0x00007FF64EDBD04F] (No symbol) [0x00007FF64EDB9614] (No symbol) [0x00007FF64EDB97B6] (No symbol) [0x00007FF64EDA8CE9] BaseThreadInitThunk [0x00007FFC4B4D259D+29] RtlUserThreadStart [0x00007FFC4C7AAF38+40]
错误原因
Selenium的ShadowRoot对象对XPath定位的支持存在兼容性限制,直接使用XPath会触发InvalidArgumentException。此外,硬编码的time.sleep可靠性差,容易因页面加载速度波动导致元素未找到。
修正方案
方案1:使用CSS选择器定位(推荐)
将Shadow Root内的元素定位方式改为CSS选择器,同时用显式等待替代time.sleep,确保元素加载完成后再操作:
from selenium import webdriver from selenium.webdriver.chrome.options import Options from selenium.webdriver.chrome.service import Service from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC from selenium.webdriver.common.by import By print(f"Checking Browser driver...") options = Options() # options.add_argument('--headless=new') options.add_argument("start-maximized") options.add_argument('--log-level=3') options.add_experimental_option("prefs", {"profile.default_content_setting_values.notifications": 1}) options.add_experimental_option("excludeSwitches", ["enable-automation"]) options.add_experimental_option('excludeSwitches', ['enable-logging']) options.add_experimental_option('useAutomationExtension', False) options.add_argument('--disable-blink-features=AutomationControlled') srv=Service() driver = webdriver.Chrome(service=srv, options=options) waitWD = WebDriverWait(driver, 10) link = "https://www.firmy.cz/kraj-liberecky/liberec/1818-liberec?q=" driver.get(link) # 显式等待Shadow Host加载完成 shadowHost = waitWD.until(EC.presence_of_element_located((By.CSS_SELECTOR, 'div.szn-cmp-dialog-container'))) shadowRoot = shadowHost.shadow_root # 显式等待Shadow Root内的按钮加载完成,并用CSS选择器定位 agree_button = waitWD.until(lambda d: shadowRoot.find_element(By.CSS_SELECTOR, 'button[data-testid="cw-button-agree-with-ads"]')) agree_button.click() input("Press!") driver.quit()
方案2:通过JavaScript执行点击
如果CSS选择器仍存在问题,可以直接用JavaScript穿透Shadow Root定位元素并点击,这种方式不受Selenium Shadow Root API限制:
from selenium import webdriver from selenium.webdriver.chrome.options import Options from selenium.webdriver.chrome.service import Service from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC from selenium.webdriver.common.by import By print(f"Checking Browser driver...") options = Options() # options.add_argument('--headless=new') options.add_argument("start-maximized") options.add_argument('--log-level=3') options.add_experimental_option("prefs", {"profile.default_content_setting_values.notifications": 1}) options.add_experimental_option("excludeSwitches", ["enable-automation"]) options.add_experimental_option('excludeSwitches', ['enable-logging']) options.add_experimental_option('useAutomationExtension', False) options.add_argument('--disable-blink-features=AutomationControlled') srv=Service() driver = webdriver.Chrome(service=srv, options=options) waitWD = WebDriverWait(driver, 10) link = "https://www.firmy.cz/kraj-liberecky/liberec/1818-liberec?q=" driver.get(link) # 等待Shadow Host出现后,用JavaScript找到按钮并点击 waitWD.until(EC.presence_of_element_located((By.CSS_SELECTOR, 'div.szn-cmp-dialog-container'))) driver.execute_script(""" const shadowHost = document.querySelector('div.szn-cmp-dialog-container'); const shadowRoot = shadowHost.shadowRoot; const agreeBtn = shadowRoot.querySelector('button[data-testid="cw-button-agree-with-ads"]'); if (agreeBtn) agreeBtn.click(); """) input("Press!") driver.quit()
关键说明
- 替换
time.sleep为显式等待:避免因页面加载延迟导致的元素未找到问题,提升代码稳定性。 - 优先使用CSS选择器:Selenium对Shadow Root内的CSS选择器支持更稳定,XPath容易触发定位错误。
- JavaScript执行兜底:当Shadow DOM结构复杂时,直接用JS操作是最可靠的方式,无需依赖Selenium的Shadow Root API。
内容的提问来源于stack exchange,提问作者Rapid1898
相关产品推荐
相关产品推荐

