Python 为什么目标阴影dom元素在第5个元素失败?

Python 为什么目标阴影dom元素在第5个元素失败?,python,windows,selenium,google-chrome,Python,Windows,Selenium,Google Chrome,最近被问及如何在chrome设置中定位元素: 有人告诉我应该使用“shadowdom”元素,所以我继续并想出了如何做到这一点 我能够使用ShadowDOM inception成功地将chrome下载页面上的搜索字段作为目标,但是当我将几乎相同的逻辑/代码应用于目标时,我就可以打开一个特定页面或一组页面chrome://settings/ ,python返回了一个错误 没有这样的元素:无法定位元素:{“方法”:“css” 选择器“,”选择器“:“启动页面上的设置”} 我如何解决这个问题 Edua

最近被问及如何在chrome设置中定位元素:

有人告诉我应该使用“shadowdom”元素,所以我继续并想出了如何做到这一点

我能够使用ShadowDOM inception成功地将chrome下载页面上的搜索字段作为目标,但是当我将几乎相同的逻辑/代码应用于目标时,我就可以打开一个特定页面或一组页面chrome://settings/ ,python返回了一个错误

没有这样的元素:无法定位元素:{“方法”:“css” 选择器“,”选择器“:“启动页面上的设置”}

我如何解决这个问题


Eduard Florinescu评论道:“当你通常也有动态内容,并且有3个以上的影子元素相互转化时,就不可能实现自动化。” 在这里:

我希望有人能解释一下这里的限制或解决方法

下面是用于定位CHROMES下载页面上搜索字段的示例代码

import selenium
from selenium import webdriver
driver = webdriver.Chrome("C:/Users/John/Desktop/Documents/selenium/webdrivers/chromedriver.exe")

#define inception function
def expand_shadow_element(element):
  shadow_root = driver.execute_script('return arguments[0].shadowRoot', element)
  return shadow_root


#start doing inception
driver.get("chrome://downloads")
root1 = driver.find_element_by_tag_name('downloads-manager')
shadow_root1 = expand_shadow_element(root1)

root2 = shadow_root1.find_element_by_tag_name('downloads-toolbar')
shadow_root2 = expand_shadow_element(root2)

root3 = shadow_root2.find_element_by_tag_name('cr-toolbar')
shadow_root3 = expand_shadow_element(root3)

root4 = shadow_root3.find_element_by_css_selector("cr-toolbar-search-field")
shadow_root4 = expand_shadow_element(root4)

root5 = shadow_root4.find_element_by_id("searchInput")

root5.send_keys('test')
下面的示例代码不适用于打开特定页面或页面集单选按钮

from selenium import webdriver
driver = webdriver.Chrome("C:/Users/John/Desktop/Documents/selenium/webdrivers/chromedriver.exe")


#define inception function
def expand_shadow_element(element):
  shadow_root = driver.execute_script('return arguments[0].shadowRoot', element)
  return shadow_root


#start doing inception
driver.get("chrome://settings/")
root1 = driver.find_element_by_tag_name('settings-ui')
shadow_root1 = expand_shadow_element(root1)

root2 = shadow_root1.find_element_by_tag_name('settings-main')
shadow_root2 = expand_shadow_element(root2)

root3 = shadow_root2.find_element_by_tag_name('settings-basic-page')
shadow_root3 = expand_shadow_element(root3)

root4 = shadow_root3.find_element_by_css_selector("settings-section")
shadow_root4 = expand_shadow_element(root4)

root5 = shadow_root4.find_element_by_css_selector("settings-on-startup-page")
shadow_root5 = expand_shadow_element(root5)

root6 = shadow_root5.find_element_by_css_selector("settings-radio-group")
shadow_root6 = expand_shadow_element(root6)

root7 = shadow_root6.find_element_by_name("4")

root7.click()
如您所见,这两个代码段在语法和结构上几乎相同,但第二个代码段不起作用

C:\Users\John\Desktop\Documents\selenium\projects\startpage_domain_test\venv\Scripts\python.exe C:/Users/John/Desktop/Documents/selenium/projects/startpage_domain_test/startpage_domain_test.py
Traceback (most recent call last):
  File "C:/Users/John/Desktop/Documents/selenium/projects/startpage_domain_test/startpage_domain_test.py", line 26, in <module>
    root5 = shadow_root4.find_element_by_css_selector("settings-on-startup-page")
  File "C:\Python37-32\lib\site-packages\selenium\webdriver\remote\webelement.py", line 430, in find_element_by_css_selector
    return self.find_element(by=By.CSS_SELECTOR, value=css_selector)
  File "C:\Python37-32\lib\site-packages\selenium\webdriver\remote\webelement.py", line 659, in find_element
    {"using": by, "value": value})['value']
  File "C:\Python37-32\lib\site-packages\selenium\webdriver\remote\webelement.py", line 633, in _execute
    return self._parent.execute(command, params)
  File "C:\Python37-32\lib\site-packages\selenium\webdriver\remote\webdriver.py", line 321, in execute
    self.error_handler.check_response(response)
  File "C:\Python37-32\lib\site-packages\selenium\webdriver\remote\errorhandler.py", line 242, in check_response
    raise exception_class(message, screen, stacktrace)
selenium.common.exceptions.NoSuchElementException: Message: no such element: Unable to locate element: {"method":"css selector","selector":"settings-on-startup-page"}
  (Session info: chrome=75.0.3770.142)


Process finished with exit code 1
C:\Users\John\Desktop\Documents\selenium\projects\startpage\u domain\u test\venv\Scripts\python.exe C:/Users/John/Desktop/Documents/selenium/projects/startpage\u domain\u test/startpage\u domain\u test.py
回溯(最近一次呼叫最后一次):
文件“C:/Users/John/Desktop/Documents/selenium/projects/startpage\u domain\u test/startpage\u domain\u test.py”,第26行,在
root5=shadow\u root4.通过\u css\u选择器(“启动页面上的设置”)查找\u元素\u
文件“C:\Python37-32\lib\site packages\selenium\webdriver\remote\webelement.py”,第430行,按css选择器查找元素
返回self.find_元素(by=by.CSS_选择器,value=CSS_选择器)
文件“C:\Python37-32\lib\site packages\selenium\webdriver\remote\webelement.py”,第659行,位于find\u元素中
{“using”:by,“value”:value})[“value']
文件“C:\Python37-32\lib\site packages\selenium\webdriver\remote\webelement.py”,第633行,在\u execute中
返回self.\u parent.execute(命令,参数)
文件“C:\Python37-32\lib\site packages\selenium\webdriver\remote\webdriver.py”,第321行,执行
self.error\u handler.check\u响应(响应)
文件“C:\Python37-32\lib\site packages\selenium\webdriver\remote\errorhandler.py”,第242行,在check\u响应中
引发异常类(消息、屏幕、堆栈跟踪)
selenium.common.exceptions.NoSuchElementException:消息:没有这样的元素:无法找到元素:{“方法”:“css选择器”,“选择器”:“启动页面上的设置”}
(会话信息:chrome=75.0.3770.142)
进程已完成,退出代码为1

看起来您只需使用
shadowRoot
s递归遍历元素

试着这样做:

def find_in_shadow_dom(css):
  return driver.execute_async_script("""
    const traverse = e => {
      let el
      if(el = e.querySelector('""" + css + """')){
        arguments[0](el)
      }
      [...e.querySelectorAll('*')].filter(e => e.shadowRoot).map(e => traverse(e.shadowRoot))
    }
    [...document.querySelectorAll('*')].filter(e => e.shadowRoot).map(e => traverse(e.shadowRoot))
    arguments[0](null)
  """)

input = find_in_shadow_dom('#searchInput')
input.send_keys('testing')
编辑:设置页面的注释。

control = find_in_shadow_dom('[label="Open a specific page or set of pages"]')
# don't forget to scroll into view
driver.execute_script("arguments[0].scrollIntoView(true)", control)
control.click()

好吧,访问shadow元素没有这样的限制。在提供正确的阴影树元素之前,您应该能够很好地访问它们

有关详细解释,请参阅答案。内容丰富且详细。

control = find_in_shadow_dom('[label="Open a specific page or set of pages"]')
# don't forget to scroll into view
driver.execute_script("arguments[0].scrollIntoView(true)", control)
control.click()
下面是您可以传递并返回元素的js

input = driver.execute_script("return document.querySelector('downloads-manager').shadowRoot.querySelector('downloads-toolbar#toolbar').shadowRoot.querySelector('cr-toolbar#toolbar').shadowRoot.querySelector('cr-toolbar-search-field#search').shadowRoot.querySelector('input#searchInput')")
input.send_keys('testing')
截图:

我能够复制粘贴此代码,并使其与上的搜索栏一起工作chrome://downloads,但当我尝试使用相同的基本结构单击chrome://settings/searchEngines 我犯了一个错误。为什么它在第一个示例中有效,而在第二个示例中无效?url=”chrome://settings/searchEngines“driver.get(url)input=driver.execute_脚本(“return document.querySelector('settings-ui')。shadowRoot.querySelector('settings-main#main'))。shadowRoot.querySelector('settings-basic-page')。shadowRoot.querySelector('settings-section')).shadowRoot.querySelector('settings-search-page').shadowRoot.querySelector('settings-animated-pages#pages').shadowRoot.querySelector('settings-search-engines-page').shadowRoot.querySelector('paper-button#addSearchEngine'))输入。单击()selenium.common.exceptions.JavascriptException:消息:javascript错误:无法读取null的属性“shadowRoot”(会话信息:chrome=76.0.3809.100),不确定要针对哪个元素。我能够成功地指向屏幕截图中所示的元素。我尝试使用此代码段,但有时会奏效,但尝试将目标锁定在屏幕上的“打开特定页面或页面集”单选按钮chrome://settings/ 返回错误AttributeError:“NoneType”对象没有属性“click”,当我尝试使用以下命令单击它时:input=find_in_shadow_dom('span[label=“打开特定页面或页面集”]”)input.click()尝试使用此函数以其父容器为目标时出现类似问题:input=find_in_shadow_dom('controlled-radio-button[label=“打开特定页面或页面集”]”)->selenium.common.exceptions.element ClickInterceptedException:Message:element单击intercepted:element在点(631418)不可单击