如何用Selenium访问多层Shadow DOM中的Fields表格元素
用Selenium穿透双层Shadow DOM获取Salesforce页面的Fields表格
直接上解决方案,核心是逐层拆解Shadow DOM:每一步先找到承载Shadow Root的宿主元素,再获取对应Shadow Root,之后在该Root内定位下一层宿主,直到触达目标表格。
完整代码示例
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 # 封装获取Shadow Root的工具函数 def get_shadow_root(driver, host_element): return driver.execute_script('return arguments[0].shadowRoot', host_element) # 初始化浏览器 driver = webdriver.Chrome() wait = WebDriverWait(driver, 20) # 最长等待20秒,避免页面加载慢导致报错 # 打开目标页面 driver.get("https://developer.salesforce.com/docs/atlas.en-us.netzero_cloud_dev_guide.meta/netzero_cloud_dev_guide/sforce_api_objects_airtravelemssnfctr.htm#maincontent") # ---------------------- 第一层Shadow DOM ---------------------- # 找到第一层Shadow DOM的宿主元素(打开F12查看页面结构,这里对应<docs-app>标签) first_host = wait.until(EC.presence_of_element_located((By.TAG_NAME, "docs-app"))) first_shadow = get_shadow_root(driver, first_host) # ---------------------- 第二层Shadow DOM ---------------------- # 在第一层Shadow Root内定位第二层宿主元素(示例为<docs-main-content>,需以实际页面结构为准) # Selenium 4+支持直接将shadow root作为查找上下文,低版本需改用first_shadow.find_element()方式 second_host = wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, "docs-main-content"), first_shadow)) second_shadow = get_shadow_root(driver, second_host) # ---------------------- 定位并提取Fields表格 ---------------------- # 先找到"Fields"标题,再定位其后续的表格元素 fields_title = wait.until(EC.presence_of_element_located((By.XPATH, "//h2[text()='Fields']"), second_shadow)) fields_table = fields_title.find_element(By.XPATH, "./following-sibling::table") # 遍历提取表格数据示例 for row in fields_table.find_elements(By.TAG_NAME, "tr"): cols = row.find_elements(By.TAG_NAME, "td") print([col.text.strip() for col in cols]) driver.quit()
关键注意事项
- 核对宿主元素:必须用浏览器F12开发者工具确认每一层Shadow DOM的宿主元素标签/选择器,示例中的标签仅作参考,需根据实际页面结构调整。
- 强制添加等待:绝对不能省略等待逻辑,页面渲染需要时间,
WebDriverWait能有效避免因元素未加载导致的NoSuchElementException。 - 版本兼容处理:若使用Selenium 3,无法将shadow root传入
EC.presence_of_element_located,需改为first_shadow.find_element(By.CSS_SELECTOR, "xxx")的方式查找内部元素。
内容的提问来源于stack exchange,提问作者JenPal
相关产品推荐
相关产品推荐

