这是适用于最新版本 Chrome 74 的解决方案。
- 导航到
chrome://extensions
- 单击详细信息按钮以获取所需的扩展
- 复制网址(其中包含您的扩展名
id)
现在我们必须导航到上面的 url,然后点击 allow in incognito 切换。
Java:
driver.get("chrome://extensions/?id=bhghoamapcdpbohphigoooaddinpkbai");
JavascriptExecutor js = (JavascriptExecutor) driver;
js.executeScript("document.querySelector('extensions-manager').shadowRoot.querySelector('#viewManager > extensions-detail-view.active').shadowRoot.querySelector('div#container.page-container > div.page-content > div#options-section extensions-toggle-row#allow-incognito').shadowRoot.querySelector('label#label input').click()");
Python:
driver.get("chrome://extensions/?id=bhghoamapcdpbohphigoooaddinpkbai")
driver.execute_script("return document.querySelector('extensions-manager').shadowRoot.querySelector('#viewManager > extensions-detail-view.active').shadowRoot.querySelector('div#container.page-container > div.page-content > div#options-section extensions-toggle-row#allow-incognito').shadowRoot.querySelector('label#label input').click()");
如果您想知道如何以及为什么,请继续阅读
根本原因:
作为 chrome 浏览器增强功能的一部分,谷歌将所有 chrome 选项移至shadow dom。所以你不能访问 allow in incognito 切换元素作为 selenium find_element 方法,它将指向页面的原始 dom。所以我们必须切换到shadow dom 并访问shadow tree 中的元素。
详情:
影子 DOM:
注意:我们将参考图片中显示的术语。所以请仔细阅读图片以便更好地理解。
解决方案:
为了使用 shadow 元素,首先我们必须找到 shadow dom 所附加的shadow host。下面是基于shadowHost获取shadow root的简单方法。
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()等操作。
shadowTreeElement.click()
当您只有一层影子 DOM 时,这看起来很简单。但是在这里,在这种情况下,我们有多个级别的 shadow dom。所以我们必须通过到达每个影子主机和根来访问元素。
下面是使用上面提到的方法(getShadowElement和getShadowRoot)的sn-p
// Locate shadowHost on the current dom
WebElement shadowHostL1 = driver.findElement(By.cssSelector("extensions-manager"));
// now locate the shadowElement by traversing all shadow levels
WebElement shadowElementL1 = getShadowElement(driver, shadowHostL1, "#viewManager > extensions-detail-view.active");
WebElement shadowElementL2 = getShadowElement(driver, shadowElementL1,"div#container.page-container > div.page-content > div#options-section extensions-toggle-row#allow-incognito");
WebElement allowToggle = shadowElementL2.findElement(By.cssSelector("label#label input"));
allowToggle.click();
您可以在答案开头提到的单个js调用中实现上述所有步骤(在下面添加只是为了减少混淆)。
WebElement allowToggle = (WebElement) js.executeScript("return document.querySelector('extensions-manager').shadowRoot.querySelector('#viewManager > extensions-detail-view.active').shadowRoot.querySelector('div#container.page-container > div.page-content > div#options-section extensions-toggle-row#allow-incognito').shadowRoot.querySelector('label#label input')");