Прокрутка веб-страницы — стандартная задача при автоматизации тестирования или парсинге данных с помощью Selenium WebDriver. Зачастую для этого используется выполнение JavaScript-кода (execute_script("window.scrollTo(...)")), но существуют сценарии, когда применение JavaScript нежелательно или невозможно. Например, при тестировании сайтов с отключенным JavaScript или при необходимости эмулировать действия пользователя максимально близко к реальности, без «искусственных» команд.
Почему избегать JavaScript для прокрутки?
- Эмуляция пользователя: Использование нативных методов Selenium для взаимодействия с браузером (нажатия клавиш, перемещение к элементам) точнее имитирует поведение реального пользователя.
- Ограничения среды: На некоторых сайтах или в специфических браузерных конфигурациях выполнение произвольного JavaScript может быть заблокировано политиками безопасности.
- Тестирование без JS: Проверка функциональности сайта при отключенном JavaScript требует альтернативных методов взаимодействия.
Альтернативные методы прокрутки в Selenium
Существует несколько подходов для прокрутки страницы в Selenium WebDriver без прямого вызова JavaScript:
- Использование эмуляции нажатия клавиш (
Keys). - Применение
Action Chainsдля перемещения к элементам. - Взаимодействие с якорями и ссылками на странице.
Рассмотрим каждый из этих методов подробнее.
Использование клавиш (Keys) для прокрутки
Класс Keys в Selenium предоставляет константы, соответствующие клавишам клавиатуры. Отправка этих клавиш активному элементу или <body> страницы может инициировать прокрутку.
Метод sendKeys(Keys.PAGE_DOWN)
Отправка Keys.PAGE_DOWN имитирует нажатие клавиши Page Down, прокручивая страницу примерно на один экран вниз. Это простой и интуитивно понятный способ.
Метод sendKeys(Keys.END) для прокрутки в конец страницы
Использование Keys.END имитирует нажатие клавиши End, что обычно приводит к мгновенной прокрутке в самый низ видимой на данный момент части документа. В случае динамической подгрузки контента может потребоваться несколько таких нажатий.
Пример кода: Прокрутка страницы вниз с использованием Keys
from selenium.webdriver.remote.webdriver import WebDriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
import time
def scroll_down_with_keys(driver: WebDriver, scrolls: int = 3):
"""Прокручивает страницу вниз несколько раз с помощью Keys.PAGE_DOWN.
Args:
driver: Экземпляр WebDriver.
scrolls: Количество прокруток страницы вниз.
"""
# Находим элемент body для отправки клавиш
body = driver.find_element(By.TAG_NAME, 'body')
print(f"Начинаем прокрутку {scrolls} раз(а) с помощью PAGE_DOWN...")
for _ in range(scrolls):
body.send_keys(Keys.PAGE_DOWN)
# Небольшая пауза для загрузки контента (если есть lazy loading)
time.sleep(0.5)
print("Прокрутка PAGE_DOWN выполнена.")
print("Прокрутка в самый конец страницы с помощью END...")
body.send_keys(Keys.END)
time.sleep(1) # Пауза для возможной подгрузки
print("Прокрутка END выполнена.")
# Пример использования:
# from selenium import webdriver
# driver = webdriver.Chrome()
# driver.get("https://some-long-page.com") # Замените на реальный URL
# scroll_down_with_keys(driver, scrolls=5)
# driver.quit()
Ограничения и особенности использования Keys
- Фокус элемента: Метод
sendKeysтребует, чтобы фокус находился на элементе, способном принимать ввод с клавиатуры (например,<body>или<input>). Если фокус находится на неинтерактивном элементе, команда может не сработать. - Динамический контент: На страницах с бесконечной прокруткой (infinite scroll) или ленивой загрузкой (lazy loading) однократное нажатие
Keys.ENDможет не привести к загрузке всего контента. Потребуются многократные нажатияKeys.PAGE_DOWNилиKeys.ENDс паузами. - Неточность:
Keys.PAGE_DOWNпрокручивает на высоту видимой области, что может варьироваться в зависимости от размера окна браузера.
Использование Action Chains для эмуляции действий пользователя
Action Chains позволяют создавать цепочки сложных пользовательских взаимодействий, таких как наведение мыши, клики, перетаскивание и, что важно для нас, перемещение к элементу, которое может вызвать прокрутку.
Что такое Action Chains и как они работают?
ActionChains — это механизм Selenium для эмуляции низкоуровневых взаимодействий. Он собирает последовательность действий (например, переместить курсор, нажать кнопку мыши) и затем выполняет их атомарно с помощью метода perform().
Прокрутка с использованием moveToElement() и perform()
Метод moveToElement(element) перемещает курсор мыши к центру указанного элемента. Если элемент находится за пределами видимой области, браузер автоматически прокрутит страницу так, чтобы элемент стал видимым. Это поведение соответствует действиям реального пользователя.
Пример кода: Прокрутка к определенному элементу с помощью Action Chains
from selenium.webdriver.remote.webdriver import WebDriver
from selenium.webdriver.remote.webelement import WebElement
from selenium.webdriver.common.by import By
from selenium.webdriver.common.action_chains import ActionChains
from selenium.common.exceptions import NoSuchElementException
import time
def scroll_to_element_with_actions(driver: WebDriver, locator: tuple[By, str]) -> bool:
"""Прокручивает страницу до видимости элемента с использованием ActionChains.
Args:
driver: Экземпляр WebDriver.
locator: Кортеж (By, "selector") для поиска элемента.
Returns:
True, если элемент найден и прокрутка выполнена, иначе False.
"""
try:
# Находим целевой элемент
element_to_scroll_to: WebElement = driver.find_element(*locator)
print(f"Элемент {locator} найден. Выполняем прокрутку...")
# Создаем цепочку действий: переместиться к элементу
actions = ActionChains(driver)
actions.move_to_element(element_to_scroll_to)
# Выполняем цепочку действий
actions.perform()
print("Прокрутка к элементу с помощью ActionChains выполнена.")
# Небольшая пауза для стабилизации страницы
time.sleep(0.5)
return True
except NoSuchElementException:
print(f"Ошибка: Элемент {locator} не найден на странице.")
return False
# Пример использования (сбор данных email-маркетинга из футера):
# from selenium import webdriver
# from selenium.webdriver.common.by import By
# driver = webdriver.Chrome()
# driver.get("https://example-marketing-site.com") # Замените на реальный URL
# footer_locator = (By.CSS_SELECTOR, "footer#site-footer .newsletter-signup")
# if scroll_to_element_with_actions(driver, footer_locator):
# print("Элемент формы подписки в футере теперь видим.")
# driver.quit()
Преимущества и недостатки подхода с Action Chains
- Преимущества:
- Высокая степень эмуляции пользовательского поведения.
- Точная прокрутка до нужного элемента.
- Работает с большинством современных веб-сайтов.
- Недостатки:
- Требует наличия конкретного элемента, до которого нужно прокрутить.
- Может быть медленнее, чем
sendKeys, если требуется прокрутить большой объем контента.
Работа с якорями (Anchors) и ссылками
Некоторые веб-страницы используют HTML-якоря (<a href="#section">) для навигации внутри страницы. Клик по такой ссылке автоматически прокручивает страницу к элементу с соответствующим id.
Суть метода: Использование ссылок на странице
Если на странице есть ссылки, ведущие к ее нижним частям (например, «О нас», «Контакты» в футере или ссылки содержания), можно найти такую ссылку и кликнуть по ней, чтобы вызвать прокрутку.
Поиск якоря на странице и клик по нему
С помощью стандартных методов поиска элементов Selenium (find_element или find_elements) можно найти нужную якорную ссылку (например, по тексту ссылки или атрибуту href) и затем использовать метод click().
Пример кода: Прокрутка к определенному разделу страницы через якорь
from selenium.webdriver.remote.webdriver import WebDriver
from selenium.webdriver.common.by import By
from selenium.common.exceptions import NoSuchElementException
import time
def scroll_using_anchor(driver: WebDriver, anchor_href: str) -> bool:
"""Ищет ссылку с указанным href (якорем) и кликает по ней для прокрутки.
Args:
driver: Экземпляр WebDriver.
anchor_href: Значение атрибута href якоря (например, "#contacts").
Returns:
True, если якорь найден и клик выполнен, иначе False.
"""
try:
# Ищем ссылку по атрибуту href
anchor_link = driver.find_element(By.CSS_SELECTOR, f'a[href="{anchor_href}"]')
print(f"Найден якорь: {anchor_href}. Выполняем клик...")
# Кликаем по ссылке
anchor_link.click()
print("Клик по якорю выполнен, страница должна была прокрутиться.")
# Пауза для завершения прокрутки
time.sleep(1)
return True
except NoSuchElementException:
print(f"Ошибка: Якорь {anchor_href} не найден на странице.")
return False
# Пример использования (переход к разделу "Портфолио" на сайте веб-студии):
# from selenium import webdriver
# driver = webdriver.Chrome()
# driver.get("https://web-studio-site.com") # Замените на реальный URL
# if scroll_using_anchor(driver, "#portfolio"):
# print("Переход к секции портфолио выполнен.")
# driver.quit()
- Ограничения: Этот метод полностью зависит от наличия подходящих якорных ссылок на странице.
Решение проблем и обходные пути
При использовании не-JavaScript методов прокрутки можно столкнуться с рядом сложностей.
Проблемы с динамическим контентом и ленивой загрузкой (Lazy Loading)
Сайты часто подгружают контент по мере прокрутки. Методы Keys.END или ActionChains.move_to_element на элемент в самом низу текущего DOM могут не сработать для загрузки всего контента.
- Решение: Комбинировать методы. Использовать
Keys.PAGE_DOWNв цикле с небольшими паузами (time.sleep) до тех пор, пока не будет загружен нужный контент или пока не будет достигнут конец страницы (например, проверяя высоту документа или наличие футера).
Обработка случаев, когда элементы перекрывают друг друга
Иногда элементы (например, «липкие» шапки или футеры, модальные окна) могут перекрывать целевой элемент, мешая ActionChains.move_to_element или клику по якорю.
- Решение: Перед прокруткой или кликом можно попытаться закрыть мешающие элементы (если есть кнопка закрытия) или использовать
Keys.PAGE_DOWN/Keys.PAGE_UPдля небольшой корректировки видимой области.
Альтернативные стратегии прокрутки для разных веб-сайтов
Не существует универсального метода, работающего идеально на всех сайтах. Лучшая стратегия — адаптивная:
- Попытаться
ActionChains: Если известен целевой элемент внизу страницы (например, футер), это самый надежный способ. - Использовать
Keys.PAGE_DOWNв цикле: Подходит для страниц с ленивой загрузкой, где нужно постепенно прокручивать вниз. - Использовать
Keys.END: Быстрый способ для статичных страниц или как первое действие перед цикломPAGE_DOWN. - Проверить наличие якорей: Если сайт использует якорную навигацию, это может быть самый простой способ.
Советы по оптимизации производительности прокрутки
- Минимизируйте паузы: Используйте
WebDriverWaitдля ожидания появления элемента вместо фиксированныхtime.sleep, где это возможно (хотя для самой прокрутки паузы часто неизбежны). - Выбирайте правильный метод: Не используйте цикл
PAGE_DOWN, если достаточно одногоENDилиmove_to_element. - Прокручивайте только при необходимости: Убедитесь, что элемент действительно находится вне видимой области, прежде чем инициировать прокрутку.
Хотя прокрутка с помощью JavaScript часто является самым прямым путем, понимание и умение применять альтернативные методы с использованием Keys и Action Chains расширяет возможности автоматизации и позволяет создавать более надежные и реалистичные тесты или парсеры.