Ни один современный сайт не обходится без JavaScript. Когда вы серфите по интернету, вы часто встречаете плавно появляющиеся элементы на странице (откройте страницу и понаблюдайте за появлением HTML тегов), элементы, которые появляются при скроллинге или при полной загрузке страницы. Вариаций использования JS много. К этому уроку у вас уже есть определенный опыт написания скриптов на Selenium. Многие программисты сталкивались с тем, что элемент, ещё не загрузился или ещё не доступен для взаимодействия с ним.
Такие ситуации будут всегда возникать при написании скриптов, так устроены современные сайты. Ранее в курсе мы обходились простыми time.sleep(), это хорошее начало, чтобы понимать, как работать с ожиданиями. Представьте, что ваш скрипт работает с множеством элементов на разных страницах сайта или даже на разных сайтах, и вдруг нужный элемент не загрузился вовремя, и скрипт упал. Уверен, вы сразу добавите в этом месте time.sleep() или даже несколько, чтобы обезопасить работу. И вот ваш скрипт «обвешан слипами», и большую часть времени ваш код спит.
Для таких ситуаций существуют неявные ожидания, или Implicit Waits. Неявное ожидание называется так, потому что его не нужно указывать отдельно, как time.sleep().
Откройте сайт, дождитесь активации кнопки и совершите клик по ней. Вы получите сообщение об успешном клике. Написать код с помощью time.sleep() для такой кнопки сложно, потому что она становится активной через 1-3 секунды после загрузки страницы, а потом снова деактивируется. Ради интереса можете попробовать написать стабильный код, используя time.sleep(). А если таких кнопок будет не одна, а десять, и все с разным таймингом?
from selenium import webdriver
from selenium.webdriver.common.by import By
with webdriver.Chrome() as browser:
browser.get('https://mob25.com/')
browser.find_element(By.ID, 'btn').click()
Давайте немного модифицируем код выше, чтобы он работал без ошибок. Применим явные ожидания. О том, как они работают, мы поговорим в следующих шагах и решим задачи на эту тему.
Запустите этот код у себя в IDE, чтобы сравнить результат работы.
import time
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.ui import WebDriverWait
with webdriver.Chrome() as browser:
browser.get('https://mob25.com/')
element = WebDriverWait(browser, 10).until(EC.element_to_be_clickable((By.ID, "btn"))).click()
time.sleep(3)
print(browser.find_element(By.ID, 'result').text)
Импортировал модуль expected_conditions из библиотеки webdriver и назвал его EC, чтобы не писать каждый раз его длинное название.
from selenium.webdriver.support import expected_conditions as EC
Импортировал сам класс для работы с ожиданиями WebDriverWait;
from selenium.webdriver.support.ui import WebDriverWait
Использовал функцию EC.element_to_be_clickable, которая ожидает пока элемент станет кликабельным;
WebDriverWait(browser, 10).until(EC.element_to_be_clickable(...
Как только элемент стал кликабельным, управление программой передается далее, и метод совершает клик по элементу.
Теперь чуть подробнее:
WebDriverWait — это класс из библиотеки Selenium, который используется для реализации явных ожиданий.
В данном случае, мы создаем объект WebDriverWait, передавая ему два аргумента:
browser: это экземпляр драйвера браузера, с которым мы работаем (в нашем случае, это Chrome).
10: это максимальное количество времени (в секундах), в течение которого WebDriverWait будет пытаться выполнить условие, указанное в методе until.
.until(…) — Этот метод указывает, какое условие мы ожидаем выполнить. Он будет опрашивать условие каждые несколько миллисекунд до тех пор, пока условие не выполнится или пока не истечет максимальное время ожидания (в данном случае 10 секунд).
EC (или expected_conditions) — это модуль в Selenium, который содержит набор предустановленных условий, которые можно использовать с WebDriverWait (далее подробно про EC).
element_to_be_clickable() — это одно из этих условий. Оно проверяет, что элемент не только присутствует на странице, но и видим, а также активен, так что по нему можно кликнуть (далее подробно про все функции).
(By.ID, «btn») — это способ указать, какой именно элемент мы ищем. В данном случае, мы ищем элемент по его идентификатору (ID), который равен «btn».