我想在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
元素中找到元素?
答案 0 :(得分:5)
有时阴影根元素是嵌套的,第二个阴影根在文档根目录中不可见,但在其父访问的阴影根中可用。我认为最好使用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个以上的影子元素时一个接一个到另一个它使自动化成为不上面的答案用于前几次工作,但只需要一个元素就可以改变位置,你需要始终使用检查元素和树一样,看看它是否在阴影根,自动化噩梦。
当您发现按钮此时无法点击时,由于阴影根和动态更改,不仅很难找到内容设置。
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()
答案 1 :(得分:2)
您可以使用driver.executeScript()
方法访问网页中的HTML元素和JavaScript对象。
在下面的示例中,executeScript
将在Promise
元素的影子树中存在的所有<a>
元素的节点列表中返回id
为{{1} }}。然后你可以执行断言测试:
host
注意:我不懂Python,所以我使用了JavaScript语法,但它应该以相同的方式工作。
答案 2 :(得分:2)
我会将其添加为评论,但我的信誉点不足–
爱德华·弗洛林内斯库(Eduard Florinescu)的答案很好地说明了这一点,即一旦进入shadowRoot,您只能使用与可用JS方法相对应的硒方法-主要是通过id选择。
为了解决这个问题,我在python字符串中编写了一个更长的JS函数,并使用了本机JS方法和属性(通过id,children + indexing等查找)来获取最终需要的元素。
当使用driver.execute_script()运行JS字符串时,您还可以使用此方法访问子元素的shadowRoots等。
答案 3 :(得分:0)
还有准备使用的 pyshadow pip 模块,它在我的情况下有效,如下示例:
from pyshadow.main import Shadow
from selenium import webdriver
driver = webdriver.Chrome('chromedriver.exe')
shadow = Shadow(driver)
element = shadow.find_element("#Selector_level1")
element1 = shadow.find_element("#Selector_level2")
element2 = shadow.find_element("#Selector_level3")
element3 = shadow.find_element("#Selector_level4")
element4 = shadow.find_element("#Selector_level5")
element5 = shadow.find_element('#control-button') #target selector
element5.click()