В процессе поиска Clear data кнопки во всплывающем окне Очистить данные просмотра, которое появляется при доступе к URL-адресу chrome://settings/clearBrowserData через Selenium, я не могу найти следующий элемент:
#shadow-root (open) <settings-privacy-page>
Моментальный снимок:
Используя Selenium ниже приведены мои пробные версии кода и обнаруженные связанные с ними ошибки:
Exception in thread "main" org.openqa.selenium.NoSuchElementException: no such element: Unable to locate element: {"method":"css selector","selector":"settings-privacy-page"}
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"); driver.manage().window().maximize(); JavascriptExecutorjs= (JavascriptExecutor) driver; WebElementclearData= (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 не предоставляет явной поддержки для работы с элементами Shadow DOM, поскольку их нет в текущем dom. Именно по этой причине мы получим NoSuchElementException исключение при попытке доступа к элементам в shadow dom.
Shadow DOM:
Примечание: Мы будем ссылаться на термины, показанные на картинке. Поэтому, пожалуйста, просмотрите картинку для лучшего понимания.
Решение:
Для работы с shadow element сначала нам нужно найти shadow host, к которому прикреплен shadow dom. Вот простой метод получения shadow root на основе shadowHost.
А затем вы можете получить доступ к элементу shadow tree с помощью элемента shadowRoot.
// get the shadowHost in the original dom using findElement WebElementshadowHost= driver.findElement(By.cssSelector("shadowHost_CSS")); // get the shadow root WebElementshadowRoot= getShadowRoot(driver,shadowHost); // access shadow tree element WebElementshadowTreeElement= shadowRoot.findElement(By.cssSelector("shadow_tree_element_css"));
Для упрощения всех вышеперечисленных шагов создан приведенный ниже метод.
И выполнять операции как обычно, например .click(), .getText().
shadowTreeElement.click()
Это выглядит просто, когда у вас есть только один уровень shadow DOM. Но здесь, в данном случае, у нас есть несколько уровней shadow doms. Таким образом, мы должны получить доступ к элементу, обращаясь к каждому теневому хосту и root.
Ниже приведен фрагмент с использованием методов, упомянутых выше (getShadowElement и getShadowRoot).
// Locate shadowHost on the current dom WebElementshadowHostL1= driver.findElement(By.cssSelector("settings-ui"));
// now locate the shadowElement by traversing all shadow levels WebElementshadowElementL1= getShadowElement(driver, shadowHostL1, "settings-main"); WebElementshadowElementL2= getShadowElement(driver, shadowElementL1,"settings-basic-page"); WebElementshadowElementL3= getShadowElement(driver, shadowElementL2,"settings-section > settings-privacy-page"); WebElementshadowElementL4= getShadowElement(driver, shadowElementL3,"settings-clear-browsing-data-dialog"); WebElementshadowElementL5= getShadowElement(driver, shadowElementL4,"#clearBrowsingDataDialog"); WebElementclearData= shadowElementL5.findElement(By.cssSelector("#clearBrowsingDataConfirm")); System.out.println(clearData.getText()); clearData.click();
Вы можете выполнить все вышеперечисленные шаги одним вызовом js, как указано в начале ответа (добавлено ниже просто для уменьшения путаницы).
Мне пришлось выполнить аналогичный тест, который требовал очистки истории просмотра Chrome. Небольшое отличие заключалось в том, что я очищал данные после перехода в расширенный раздел всплывающего окна. Поскольку вы изо всех сил пытаетесь нажать только кнопку "Очистить данные", я совершенно уверен, что вы по ошибке пропустили один или два элемента иерархии. Или, возможно, перепутали дочерние и родительские элементы. Судя по вашему коду, я предполагаю, что вы уже знаете, что для доступа к определенному элементу shadow DOM вам нужна правильная последовательность, и это также было довольно подробно объяснено выше. Переходя непосредственно к вашей проблеме, вот мой фрагмент кода, который работает правильно. Код ожидает, пока данные не будут очищены, а затем перейдет к следующему действию-
WebDriverWaitwait=newWebDriverWait(driver, 15); driver.get("chrome://settings/clearBrowserData"); // Get shadow root elements WebElementshadowRoot1= expandRootElement(driver.findElement(By.xpath("/html/body/settings-ui")));
В вашем случае это также должно работать должным образом, если вы не собираетесь изменять какие-либо параметры, выбранные по умолчанию во всплывающем окне (в этом случае вам придется добавить еще несколько кодов, касающихся установки этих флажков). Пожалуйста, скажите мне, решит ли это вашу проблему. Надеюсь, это полезно Я также добавил снимок экрана сюда - изображение
Однако, когда нужный элемент открывается из shadow-dom, вам нужно вызвать WebDriverWait для elementToBeClickable(), и вы можете предложить следующее решение:
Я получал InvalidArgumentException при попытке идентифицировать элемент shadowRoot в DOM с использованием Selenium 4.3.0 и Chrome версии 103.0.5060.134
Решение этой проблемы заключается в SearchContext se= driver.findElment(By.locator("...").getShadowRoot(); тип возвращаемого значения - SearchContext в строке выше попробуйте использовать locator как xpath и, во-вторых, попытайтесь найти элемент, используя ссылку SearchContext, например
WebElement we= se.findElement(By.locator(".....")); use locater as cssSelector
И бум, это работает как шарм
Я не нашел это решение доступным, и мне потребовалось полдня, чтобы разобраться, Надеюсь, это поможет!!!