最近询问如何在 chrome 设置中定位元素:How to edit chromes search and homepage with selenium/python?
有人告诉我应该使用“shadow dom”元素,所以我继续思考如何做到这一点。
我能够使用 Shadow dom inception 成功定位 chrome 下载页面上的搜索字段,但是当应用几乎相同的逻辑/代码来定位在 chrome://settings/上打开特定页面或一组页面时,python返回错误
no such element: Unable to locate element: {"method":"css selector","selector":"settings-on-startup-page"}
如何解决这个问题?
<小时/>Eduard Florinescu 评论道:“当您通常同时拥有动态内容和超过 3 个阴影元素时,就不可能实现自动化。” 这里:How to handle elements inside Shadow DOM from Selenium
我希望有人可以解释这里的限制或解决方法?
这里是用于定位 Chrome 下载页面上的搜索字段的示例代码
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
最佳答案
看起来您只需要使用 shadowRoot
递归遍历元素即可。
尝试这样:
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()
关于python - 为什么定位 Shadow dom 元素在第 5 个元素处失败?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57367383/