我想在chromedriver中自动执行文件下载完成检查。下载列表中每个条目的HTML如下所示
<a is="action-link" id="file-link" tabindex="0" role="link" href="http://fileSource" class="">DownloadedFile#1</a>因此,我使用以下代码来查找目标元素:
driver.get('chrome://downloads/') # This page should be available for everyone who use Chrome browser
driver.find_elements_by_tag_name('a')当有3个新的下载时,这将返回空列表。
据我所知,只有#shadow-root (open)标记的父元素才能被处理。那么怎样才能在这个#shadow-root元素中找到元素呢?
发布于 2018-02-13 06:40:20
有时,影子根元素是嵌套的,并且第二个影子根在文档根中不可见,但在其父访问的影子根中可用。我认为最好是使用selenium选择器并注入脚本来获取卷影根:
def expand_shadow_element(element):
shadow_root = driver.execute_script('return arguments[0].shadowRoot', element)
return shadow_root
outer = expand_shadow_element(driver.find_element_by_css_selector("#test_button"))
inner = outer.find_element_by_id("inner_button")
inner.click()为了把这个放到透视图中,我刚刚用Chrome的下载页面添加了一个可测试的例子,点击搜索按钮需要打开3个嵌套的影子根元素:

import selenium
from selenium import webdriver
driver = webdriver.Chrome()
def expand_shadow_element(element):
shadow_root = driver.execute_script('return arguments[0].shadowRoot', element)
return shadow_root
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_css_selector('downloads-toolbar')
shadow_root2 = expand_shadow_element(root2)
root3 = shadow_root2.find_element_by_css_selector('cr-search-field')
shadow_root3 = expand_shadow_element(root3)
search_button = shadow_root3.find_element_by_css_selector("#search-button")
search_button.click()执行其他答案中建议的相同方法的缺点是,它对查询进行硬编码,可读性较差,并且您不能将中间选择用于其他操作:
search_button = driver.execute_script('return document.querySelector("downloads-manager").shadowRoot.querySelector("downloads-toolbar").shadowRoot.querySelector("cr-search-field").shadowRoot.querySelector("#search-button")')
search_button.click()稍后编辑:
我最近尝试访问内容设置(参见下面的代码),它有多个阴影根元素叠加,现在你不能访问其中一个,除非首先扩展另一个,当你通常也有动态内容和超过3个阴影元素一个到另一个时,这使得自动化变得不可能。上面的答案在几次前是有效的,但只需要一个元素改变位置就足够了,你需要始终使用inspect元素并在树上向上移动,看看它是否在阴影根中,自动化噩梦。
不仅很难找到内容设置,因为阴影和动态变化,当你发现按钮在这一点上是不可点击的。
driver = webdriver.Chrome()
def expand_shadow_element(element):
shadow_root = driver.execute_script('return arguments[0].shadowRoot', element)
return shadow_root
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_css_selector('[page-name="Settings"]')
shadow_root2 = expand_shadow_element(root2)
root3 = shadow_root2.find_element_by_id('search')
shadow_root3 = expand_shadow_element(root3)
search_button = shadow_root3.find_element_by_id("searchTerm")
search_button.click()
text_area = shadow_root3.find_element_by_id('searchInput')
text_area.send_keys("content settings")
root0 = shadow_root1.find_element_by_id('main')
shadow_root0_s = expand_shadow_element(root0)
root1_p = shadow_root0_s.find_element_by_css_selector('settings-basic-page')
shadow_root1_p = expand_shadow_element(root1_p)
root1_s = shadow_root1_p.find_element_by_css_selector('settings-privacy-page')
shadow_root1_s = expand_shadow_element(root1_s)
content_settings_div = shadow_root1_s.find_element_by_css_selector('#site-settings-subpage-trigger')
content_settings = content_settings_div.find_element_by_css_selector("button")
content_settings.click()发布于 2016-05-23 18:10:14
可以使用driver.executeScript()方法访问网页中的HTML元素和JavaScript对象。
在下面的示例中,executeScript将在Promise中返回id为host的元素的影子树中存在的所有<a>元素的节点列表。然后,您可以执行断言测试:
it( 'check shadow root content', function ()
{
return driver.executeScript( function ()
{
return host.shadowRoot.querySelectorAll( 'a' ).then( function ( n )
{
return expect( n ).to.have.length( 3 )
}
} )
} ) 注意:我不懂Python,所以我使用了JavaScript语法,但它的工作方式应该是一样的。
发布于 2019-05-21 01:16:52
我想添加这条评论,但我没有足够的名誉点--
Eduard Florinescu的回答很好地说明了一点,即一旦进入shadowRoot,就只能使用与可用的JS方法相对应的selenium方法--主要是select by id。
为了解决这个问题,我在python字符串中编写了一个更长的JS函数,并使用原生JS方法和属性(通过id查找、子对象+索引等)。来获得我最终需要的元素。
当使用driver.execute_script()运行JS字符串时,还可以使用此方法访问子元素的shadowRoots等
https://stackoverflow.com/questions/37384458
复制相似问题