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

如何通过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 &quot;Unknown Unknown.&quot;" 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 &amp;&amp; $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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.13 15:55:58