如何通过Selenium Python访问Shadow Root(Salesforce Lightning场景)
Salesforce Lightning中Selenium Python访问Shadow-Root失败问题
问题描述
在Salesforce Lightning Experience环境中,使用Selenium Python尝试访问动态选择框的shadow-root标签始终失败,需求是向shadow-root内的<div>Unknown Place</div>元素输入字符串,模拟手动输入操作。
相关HTML结构
<input type="text" autocomplete="off" tabindex="0" aria-expanded="true" aria-label="Search for your place below. If it is not listed, select "Unknown Unknown."" aria-owns="ui-select-choices-0" class="form-control ui-select-search ng-pristine ng-valid ng-not-empty ng-touched" placeholder="Please enter 3 or more characters" ng-model="$select.search" ng-show="$select.searchEnabled && $select.open" aria-activedescendant="ui-select-choices-row-0-0" style="width: 686px;"> #shadow-root (user-agent) <div pseudo="-webkit-input-placeholder" id="placeholder" style="display: none !important;">Please enter 3 or more characters</div> <div>Unknown Place</div>
现有实现代码
测试类
import unittest import os import page from selenium import webdriver from selenium.webdriver.chrome.service import Service class Application(unittest.TestCase): def setUp(self): chromedrive_path = os.getenv("CHROMEDRIVER_PATH") service = Service(executable_path=chromedrive_path) self.driver = webdriver.Chrome(service=service) self.driver.implicitly_wait(10) self.driver.get("https://some.url.com") self.driver.maximize_window() def test_case_one(self): main_page.foo() def tearDown(self): self.driver.close() if __name__ == "__main__": unittest.main()
页面类
import time import os from locator import * from element import BasePageElement from selenium.webdriver.support.select import Select from selenium.webdriver.common.keys import Keys from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions class Non_Shadow_Dom_Element(BasePageElement): locator = MainPageLocator.non_shadow_dom_element class Shadow_Dom_Root_Element(BasePageElement): locator = MainPageLocator.shadow_dom_root_element class BasePage(): def __init__(self, driver): self.driver = driver class MainPage(BasePage): def foo(self): # Locate the shadow host element shadow_host = self.driver.find_element(*MainPageLocator.non_shadow_dom_element) # This didnt work # shadow_root = shadowHost.getShadowRoot(); # Access the shadow root shadow_root = driver.execute_script("return arguments[0].shadowRoot", shadow_host) # Find an element inside the shadow root shadow_element = shadow_root.find_element(*MainPageLocator.shadow_dom_root_element) print("Shadow Element Text:", shadow_element.text) time.sleep(5)
定位器代码
from selenium.webdriver.common.by import By class MainPageLocator(): non_shadow_dom_element = (By.CSS_SELECTOR, "input[placeholder='Please enter 3 or more characters']") shadow_dom_root_element = (By.CSS_SELECTOR, "input[placeholder='Please enter 3 or more characters']div") #Im not 100% sure how to reach this tag.
当前问题
执行代码后输出始终为Shadow Root: None,期望输出为Shadow Root: Unknown Place。环境信息:Python 3.13.2,Selenium 4.29.0。
问题分析与修复
1. Shadow Root获取错误
代码中shadow_root = driver.execute_script("return arguments[0].shadowRoot", shadow_host)未使用self.driver,类方法中必须通过self调用实例属性,否则无法正确执行脚本获取shadow root。
2. 定位器错误
shadow_dom_root_element的CSS选择器冗余:进入shadow root内部后,无需重复指定外部input的选择器,直接定位内部目标元素即可。
3. 操作逻辑错误
shadow-root内的<div>Unknown Place</div>是input的渲染内容,直接修改该div不会触发表单绑定的业务逻辑,正确做法是直接向外部input元素输入文本,通过ng-model同步更新渲染内容。
修复后的代码
页面类修改
class MainPage(BasePage): def foo(self): # Locate the shadow host element shadow_host = self.driver.find_element(*MainPageLocator.non_shadow_dom_element) # 修复:使用self.driver执行脚本,或直接用Selenium 4+原生API shadow_root = self.driver.execute_script("return arguments[0].shadowRoot", shadow_host) # 可选:Selenium 4.0+支持直接调用shadow_root属性 # shadow_root = shadow_host.shadow_root # 定位shadow root内的目标div shadow_element = shadow_root.find_element(*MainPageLocator.shadow_dom_root_element) print("Shadow Element Text:", shadow_element.text) # 正确操作:直接向input输入文本,触发绑定逻辑 shadow_host.send_keys("Your Target Place") time.sleep(5)
定位器修改
class MainPageLocator(): non_shadow_dom_element = (By.CSS_SELECTOR, "input[placeholder='Please enter 3 or more characters']") # 修复:直接定位shadow root内的非placeholder div shadow_dom_root_element = (By.CSS_SELECTOR, "div:not([id='placeholder'])")
内容的提问来源于stack exchange,提问作者user6315807
相关产品推荐
相关产品推荐

