无法使用 Selenium 和 Python 在 #shadow-root (open) 中找到登录元素

问题描述 投票:0回答:5

我正在尝试使用 selenium 来自动执行某些操作,但无法找到页面上的第一个元素 https://developer.servicenow.com/dev.do 因此无法登录

from selenium import webdriver
from selenium.webdriver.common.keys import Keys

driver_path = "../bin/chromedriver.exe"
driver = webdriver.Chrome(driver_path)

driver.get("https://developer.servicenow.com/dev.do")

driver.find_element_by_xpath("/html/body/dps-app//div/header/dps-navigation-header//header/div/div[2]/ul/li[3]/dps-login//div/dps-button//button/span")

我收到错误

selenium.common.exceptions.NoSuchElementException: Message: no such element: Unable to locate element: {"method":"xpath","selector":"/html/body/dps-app//div/header/dps-navigation-header//header/div/div[2]/ul/li[3]/dps-login//div/dps-button//button/span"}
python selenium css-selectors shadow-dom queryselector
5个回答
4
投票

登录 按钮位于多个

#shadow-root (open)

深处

shadow-root-open-multiple


解决方案

Tto

click()
在所需元素上,您可以使用
shadowRoot.querySelector()
并且可以使用以下定位器策略

from selenium import webdriver

options = webdriver.ChromeOptions() 
options.add_argument("start-maximized")
options.add_experimental_option("excludeSwitches", ["enable-automation"])
options.add_experimental_option('useAutomationExtension', False)
driver = webdriver.Chrome(options=options, executable_path=r'C:\WebDrivers\chromedriver.exe')
driver.get('https://developer.servicenow.com/dev.do')
SignInButton = driver.execute_script("return document.querySelector('dps-app').shadowRoot.querySelector('dps-navigation-header').shadowRoot.querySelector('header.dps-navigation-header dps-login').shadowRoot.querySelector('dps-button')")
SignInButton.click()
        
  • 浏览器快照:

shadow-root-open


参考文献

您可以在以下位置找到一些相关的详细讨论:


0
投票

您可以在 servicenow 商店中查看 Automatepro 应用程序。 它使用 selenium,但他们在幕后预先编写了 selenium,以便与所有 servicenow UI 组件进行交互,包括那些使用 Shadow DOM 的组件。 您只需选择 UI 元素并提供测试数据。 我们发现它节省了我们自己编写和维护 selenium 代码的大量时间..


0
投票

这个解决方案正是我正在寻找的使用 Powershell 登录我的实例的解决方案。

driver.executescript("return document.querySelector('dps-app').shadowRoot.querySelector('dps-navigation-header').shadowRoot.querySelector('header.dps-navigation-header dps-login').shadowRoot.querySelector('dps-button')").Click()

0
投票

我写了一篇博客,在这里回答了您的很多问题:

https://www.seamlessmigration.com/servicenow-selenium-shadown-doms/

编辑:我使用shadow root写了一篇更好的博客来更好地解决这个问题

https://www.seamlessmigration.com/part-2-servicenow-selenium-shadow-dom/

# 1. Locate the Shadow Host
# First, identify the shadow host element using its CSS selector:
shadow_host = driver.find_element(By.CSS_SELECTOR, "shadow-host-selector") 
 
# 2. Access the Shadow Root
shadow_root = shadow_host.shadow_root 
 
# 3. Find the Element within the Shadow DOM
# With the shadow root exposed,
# you can now interact with elements inside it using regular CSS selectors:
element_in_shadow = shadow_root.find_element(By.CSS_SELECTOR, "inner-element-selector") 

使用时需要注意的两点

shadow_root

  1. ShadowRoot 中的功能有限: ShadowRoot 仅支持 find_element、find_elements 和 session,不像 WebElement 提供了多种交互方式。
  2. 选择器限制: ShadowRoot 中只允许使用 CSS_SELECTOR,其他选择器(如 XPath)不起作用。

-1
投票

我认为这是因为您试图在网站有时间加载所有元素之前访问“登录”。

我建议你使用

driver.set_page_load_timeout(120)

因此,在网站上加载所有内容后,selenium 会寻找按钮。

© www.soinside.com 2019 - 2024. All rights reserved.