Привет!)
Возникали ситуации, когда стандартных методов поиска веб-элементов не хватало для полноценной автоматизации? То кнопка не нажимается, то элемент перекрывается, то не подгружается. У всего этого есть разные причины и самые разные решения.
В этой статье как раз таки рассмотрим некоторые из таких проблем.
Для тех кому не интересна база

Ссылочка на тележку

Стандартные методы работы с веб-элементами и нестандартные проблемы

Всем известно, что основные методы поиска элементов в Selenium - find_element и find_elements , которые находят один или несколько элементов соответственно.
Также, все мы знаем, что есть различные селекторы, такие как id, name, xpath, css . Но интересным моментом является, что поиск по id или name осуществляется быстрее, чем тот же поиск по xpath или css .
Почему? Достаточно просто объяснить: id, как идентификатор, по хорошему, должен быть уникальным в пределах всего HTML-документа. В таком случае, браузер или JS движок может найти элемент не просматривая весь DOM.

DOM (Document Object Model) - иерархическая структура, которая представляет собой внутреннее представление веб-страницы в браузере.

С name примерно та же история, атрибут может быть не уникальным, однако, зачастую, элементы с одинаковым именем сгруппированы по типу.
Что же касается css и xpath - они могут включать в себя различные критерии выбора (классы, атрибуты, вложенность), что делает их обработку более сложной. Зачастую, селекторы составные и требуют более детального анализа дерева документов.

Также не забудем про самые обычные методы для взаимодействия с веб-элементами: click, send_keys . Зачастую найдя элемент по селектору, условную кнопку, мы можем с этим элементом взаимодействовать, например - кликнуть.

driver.find_element(By.LINK_TEXT, "More information...").click()

Но бывают и не совсем стандартные ситуации.

ElementClickInterceptedException. Элемент накрыло

На самом деле ошибка встречается довольно таки часто. И имеет пару вариантов решения:

Лучший из них - анализ DOM страницы.
Может быть вариант, что перекрывающий элемент - лоадер и стоит просто немного подождать его исчезновения. Можно использовать следующий код для того, чтобы дождаться лоадера:

WebDriverWait(driver, 20).until(EC.invisibility_of_element_located(By.NAME, "loaderName"))

Или может быть вариант, что элемент всегда перекрывается другим.
В таком случае мы можем попробовать перейти выше или ниже по DOM страницы к родительскому или дочернему элементу, чтобы совершить нужное действие.
Но если перекрывающий элемент полностью блокирует взаимодействие с нужным элементом, то можно имитировать нажатие мышкой на кнопку. Selenium предлагает нам ActionChains, который можно использовать следующим образом:

Из документации:

ActionChains - это способ автоматизации низкоуровневых взаимодействий, таких как перемещения мыши, действия с кнопками мыши, нажатия клавиш и взаимодействия с контекстным меню.

from selenium.webdriver.common.action_chains import ActionChains

filter_field = WebDriverWait(driver, 20).until(EC.element_to_be_clickable(By.ID, "filter"))
ActionChains(driver).move_to_element(filter_field).click().perform()

iframe. 25-й кадр

Иногда ошибка может быть связана с фреймом. Что это?

iframe (inline frame) - HTML-элемент, который позволяет встраивать один документ HTML-документ внутрь другого. Иными словами - позволяет загружать и отображать содержимое другого веб-ресурса.

Вместе с тем, это зачастую вызывает TimeoutException , хоть и элемент находится в DOM страницы. Пример iframe в DOM:

Зачастую решением данной проблемы является переход на frame посредством следующего кода:

driver.switch_to.frame(WebDriverWait(driver, 20).until(EC.visibility_of_element_located(By.ID, "window_frame")))

Мои мысли

В целом, решение большей части проблем заключается в понимании того, что есть DOM.
Некоторые проблемы могут помочь обойти Chrome-опции: ссылочка на статью.

Комментарии (1)