Урок 11. Работа с динамическим контентом и AJAX через Selenium

На многих современных сайтах контент загружается динамически с помощью JavaScript и AJAX. Это значит, что при первоначальной загрузке страницы нужные данные могут отсутствовать, и их нужно подождать перед парсингом. Selenium позволяет эффективно справляться с такими случаями.

Что такое динамический контент

Динамический контент – это элементы страницы, которые подгружаются после первоначальной загрузки страницы. Чаще всего это списки товаров, статьи, отзывы, рейтинги. Без ожидания загрузки такие элементы будут пустыми.

Пример: ожидание элементов с помощью WebDriverWait

from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
import time

# Указываем путь к сохраненному драйверу
service = Service(r".\drivers\chromedriver.exe")

options = webdriver.ChromeOptions()
# options.add_argument('--headless')  # Раскомментировать, если нужно скрыть браузер

driver = webdriver.Chrome(service=service, options=options)
driver.get("https://books.toscrape.com/catalogue/category/books_1/index.html")

wait = WebDriverWait(driver, 10)
page_count = 0
max_pages = 5

while page_count < max_pages:
    books = wait.until(
        EC.presence_of_all_elements_located((By.CSS_SELECTOR, "article.product_pod"))
    )

    for book in books:
        title = book.find_element(By.CSS_SELECTOR, "h3 a").get_attribute("title").strip()
        price = book.find_element(By.CSS_SELECTOR, "p.price_color").text.strip()
        print(f"{title} - {price}")

    page_count += 1

    try:
        next_button = driver.find_element(By.CSS_SELECTOR, "li.next a")
        next_button.click()
        time.sleep(2)
    except:
        print("Больше страниц нет.")
        break

driver.quit()

Пояснение

  1. Открытие браузера и переход на страницу — Selenium запускает Chrome и загружает сайт с динамическим контентом.
  2. Ожидание элементов (WebDriverWait) — важно для динамического контента, чтобы элементы, которые подгружаются после загрузки страницы, были доступны для обработки.
  3. Сбор данных из элементов — скрипт получает название книги и цену с каждой страницы.
  4. Пагинация — с помощью кнопки «Next» скрипт автоматически переходит на следующую страницу, пока не достигнет лимита (max_pages = 5).
  5. Закрытие браузера — по завершении работы Selenium корректно закрывает окно.

Советы при работе с AJAX и динамическим контентом

  • Используйте WebDriverWait вместо time.sleep() для более стабильного ожидания элементов
  • Учитывайте, что элементы могут появляться с задержкой, поэтому используйте условие presence_of_all_elements_located
  • Если нужно дождаться кликабельности кнопки, используйте element_to_be_clickable
  • Для списков, которые подгружаются при скролле, можно сочетать ожидание и плавную прокрутку страницы

Пример: плавная прокрутка и ожидание подгрузки

import time
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.common.by import By
from selenium.webdriver.common.action_chains import ActionChains
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

service = Service(r".\drivers\chromedriver.exe")
options = webdriver.ChromeOptions()
driver = webdriver.Chrome(service=service, options=options)
driver.get("https://quotes.toscrape.com/scroll")

wait = WebDriverWait(driver, 10)

collected = set()  # для уникальных цитат
scroll_pause = 0.3
max_empty_scrolls = 10  # сколько скроллов без новых элементов остановить

empty_scrolls = 0
last_count = 0

while empty_scrolls < max_empty_scrolls:
    driver.execute_script("window.scrollBy(0, 300);")
    time.sleep(scroll_pause)

    quotes = driver.find_elements(By.CSS_SELECTOR, "div.quote")
    if len(quotes) > last_count:
        last_count = len(quotes)
        empty_scrolls = 0
    else:
        empty_scrolls += 1

# Собираем все цитаты после полной прокрутки
quotes = driver.find_elements(By.CSS_SELECTOR, "div.quote")
for quote in quotes:
    text = quote.find_element(By.CSS_SELECTOR, "span.text").text.strip()
    author = quote.find_element(By.CSS_SELECTOR, "small.author").text.strip()
    if text not in collected:
        collected.add(text)
        ActionChains(driver).move_to_element(quote).perform()  # видимая прокрутка
        print(f"{text} — {author}")
        time.sleep(0.05)

input("Нажмите Enter, чтобы закрыть браузер...")
driver.quit()

Как работает код бесконечной прокрутки в Selenium

  1. Скролл вниз по странице:

    driver.execute_script("window.scrollBy(0, 300);") — прокручиваем страницу на 300px за один шаг. После каждого шага делаем паузу time.sleep(0.3), чтобы динамический контент успел подгрузиться.

  2. Проверка новых элементов:

    Мы отслеживаем, появились ли новые цитаты после прокрутки: quotes = driver.find_elements(By.CSS_SELECTOR, "div.quote")
    if len(quotes) > last_count:
      last_count = len(quotes)
      empty_scrolls = 0
    else:
      empty_scrolls += 1
    Цикл продолжается, пока есть новые элементы или пока не достигнуто max_empty_scrolls пустых скроллов.

  3. Сбор всех элементов после полной прокрутки:

    После завершения скролла получаем список всех цитат: quotes = driver.find_elements(By.CSS_SELECTOR, "div.quote")

  4. Вывод текста с видимой прокруткой:

    Скроллим к каждому элементу и одновременно выводим текст: ActionChains(driver).move_to_element(quote).perform()
    print(f"{'{text}'} — {'{author}'}")
    Таким образом браузер визуально прокручивается к каждому элементу.

Итого: сначала браузер прокручивает страницу вниз, чтобы загрузились все цитаты. Затем мы идём по списку всех цитат и выводим их текст, прокручивая к каждой цитате для визуального эффекта. Отката вверх автоматически не происходит.

Для более живого эффекта можно выводить текст прямо во время скролла, как будто пользователь листает страницу и видит новые цитаты сразу.

Используя Selenium с ожиданиями и скроллом, вы можете парсить динамический контент и получать полные данные с сайтов, которые активно используют AJAX.

Больше уроков по парсингу на parsertools.ru/lessons.