我一直在关注如何使用selenium自动实现阴影DOM元素的讨论。与#shadow-root (open) 元素一起工作。
在通过“ selenium”访问url时出现Clear data的“ 清除浏览数据”弹出窗口中定位按钮的过程中,我无法找到 以下元素: chrome://settings/clearBrowserData
chrome://settings/clearBrowserData
#shadow-root (open) <settings-privacy-page>
快照:
使用Selenium,以下是我的代码试用以及遇到的相关错误:
尝试1:
WebElement root5 = shadow_root4.findElement(By.tagName("settings-privacy-page"));
错误:
Exception in thread "main" org.openqa.selenium.JavascriptException: javascript error: b.getElementsByTagName is not a function
尝试2:
WebElement root5 = shadow_root4.findElement(By.cssSelector("settings-privacy-page"));
Exception in thread "main" org.openqa.selenium.NoSuchElementException: no such element: Unable to locate element: {"method":"css selector","selector":"settings-privacy-page"}
尝试3:
WebElement root5 = (WebElement)((JavascriptExecutor)shadow_root4).executeScript("return document.getElementsByTagName('settings-privacy-page')[0]");
Exception in thread "main" java.lang.ClassCastException: org.openqa.selenium.remote.RemoteWebElement cannot be cast to org.openqa.selenium.JavascriptExecutor
如果有帮助的话,初始代码块(至上一行)可以 完美工作:
driver.get("chrome://settings/clearBrowserData"); WebElement root1 = driver.findElement(By.tagName("settings-ui")); WebElement shadow_root1 = expand_shadow_element(root1); WebElement root2 = shadow_root1.findElement(By.cssSelector("settings-main#main")); WebElement shadow_root2 = expand_shadow_element(root2); WebElement root3 = shadow_root2.findElement(By.cssSelector("settings-basic-page[role='main']")); WebElement shadow_root3 = expand_shadow_element(root3); WebElement root4 = shadow_root3.findElement(By.cssSelector("settings-section[page-title='Privacy and security']")); WebElement shadow_root4 = expand_shadow_element(root4);
PS:expand_shadow_element()作品完美无缺。
如果您尝试获取“清除数据”元素,则可以使用下面的js获取该元素然后执行。
return document.querySelector('settings-ui').shadowRoot.querySelector('settings-main').shadowRoot.querySelector('settings-basic-page').shadowRoot.querySelector('settings-section > settings-privacy-page').shadowRoot.querySelector('settings-clear-browsing-data-dialog').shadowRoot.querySelector('#clearBrowsingDataDialog').querySelector('#clearBrowsingDataConfirm')
这是示例脚本。
driver.get("chrome://settings/clearBrowserData"); driver.manage().window().maximize(); JavascriptExecutor js = (JavascriptExecutor) driver; WebElement clearData = (WebElement) js.executeScript("return document.querySelector('settings-ui').shadowRoot.querySelector('settings-main').shadowRoot.querySelector('settings-basic-page').shadowRoot.querySelector('settings-section > settings-privacy-page').shadowRoot.querySelector('settings-clear-browsing-data-dialog').shadowRoot.querySelector('#clearBrowsingDataDialog').querySelector('#clearBrowsingDataConfirm')"); // now you can click on clear data button clearData.click();
编辑2:解释
问题: Selenium不提供对ShadowDOM元素的明确支持,因为它们不在当前dom中。这就是为什么NoSuchElementException当尝试访问中的元素时我们将获得异常的原因shadow dom。注意:我们将参考图片中显示的术语。
解:
为了与之一起工作,shadow element我们必须找到shadow host暗影穹顶所连接的。这是基于shadowHost 获取影子根的简单方法。
private static WebElement getShadowRoot(WebDriver driver,WebElement shadowHost) { JavascriptExecutor js = (JavascriptExecutor) driver; return (WebElement) js.executeScript("return arguments[0].shadowRoot", shadowHost); }
然后,您可以使用shadowRoot元素访问阴影树元素。
// get the shadowHost in the original dom using findElement WebElement shadowHost = driver.findElement(By.cssSelector("shadowHost_CSS")); // get the shadow root WebElement shadowRoot = getShadowRoot(driver,shadowHost); // access shadow tree element WebElement shadowTreeElement = shadowRoot.findElement(By.cssSelector("shadow_tree_element_css"));
为了简化上述所有步骤,创建了以下方法。
public static WebElement getShadowElement(WebDriver driver,WebElement shadowHost, String cssOfShadowElement) { WebElement shardowRoot = getShadowRoot(driver, shadowHost); return shardowRoot.findElement(By.cssSelector(cssOfShadowElement)); }
现在您可以通过单个方法调用获取shadowTree元素
WebElement shadowHost = driver.findElement(By.cssSelector("shadowHost_CSS_Goes_here)); WebElement shadowTreeElement = getShadowElement(driver,shadowHost,"shadow_tree_element_css");
并执行操作如常一样.click(),.getText()。
sh``` adowTreeElement.click()
当您只有一个级别的影子DOM时,这看起来很简单。但是在这里,在 这种情况下,我们有多个级别的阴影域。因此,我们必须 通过到达每个影子主机和根来访问元素。 以下是使用上述方法的代码段(getShadowElement和getShadowRoot)
// Locate shadowHost on the current dom WebElement shadowHostL1 = driver.findElement(By.cssSelector(“settings-ui”));
// now locate the shadowElement by traversing all shadow levels WebElement shadowElementL1 = getShadowElement(driver, shadowHostL1, “settings-main”); WebElement shadowElementL2 = getShadowElement(driver, shadowElementL1,”settings-basic-page”); WebElement shadowElementL3 = getShadowElement(driver, shadowElementL2,”settings-section > settings-privacy-page”); WebElement shadowElementL4 = getShadowElement(driver, shadowElementL3,”settings-clear-browsing-data-dialog”); WebElement shadowElementL5 = getShadowElement(driver, shadowElementL4,”#clearBrowsingDataDialog”); WebElement clearData = shadowElementL5.findElement(By.cssSelector(“#clearBrowsingDataConfirm”)); System.out.println(clearData.getText()); clearData.click();
您可以按照答案开头所述在单个js调用中完成上述所有步骤(以下添加只是为了减少混乱)。
WebElement clearData = (WebElement) js.executeScript(“return document.querySelector(‘settings-ui’).shadowRoot.querySelector(‘settings-main’).shadowRoot.querySelector(‘settings-basic-page’).shadowRoot.querySelector(‘settings-section > settings-privacy-page’).shadowRoot.querySelector(‘settings-clear-browsing-data-dialog’).shadowRoot.querySelector(‘#clearBrowsingDataDialog’).querySelector(‘#clearBrowsingDataConfirm’)”); ```