Урок 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()
Пояснение
- Открытие браузера и переход на страницу — Selenium запускает Chrome и загружает сайт с динамическим контентом.
- Ожидание элементов (WebDriverWait) — важно для динамического контента, чтобы элементы, которые подгружаются после загрузки страницы, были доступны для обработки.
- Сбор данных из элементов — скрипт получает название книги и цену с каждой страницы.
- Пагинация — с помощью кнопки «Next» скрипт автоматически переходит на следующую страницу, пока не достигнет лимита (max_pages = 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
-
Скролл вниз по странице:
driver.execute_script("window.scrollBy(0, 300);")— прокручиваем страницу на 300px за один шаг. После каждого шага делаем паузуtime.sleep(0.3), чтобы динамический контент успел подгрузиться. -
Проверка новых элементов:
Мы отслеживаем, появились ли новые цитаты после прокрутки:
quotes = driver.find_elements(By.CSS_SELECTOR, "div.quote")Цикл продолжается, пока есть новые элементы или пока не достигнуто
if len(quotes) > last_count:
last_count = len(quotes)
empty_scrolls = 0
else:
empty_scrolls += 1max_empty_scrollsпустых скроллов. -
Сбор всех элементов после полной прокрутки:
После завершения скролла получаем список всех цитат:
quotes = driver.find_elements(By.CSS_SELECTOR, "div.quote") -
Вывод текста с видимой прокруткой:
Скроллим к каждому элементу и одновременно выводим текст:
ActionChains(driver).move_to_element(quote).perform()Таким образом браузер визуально прокручивается к каждому элементу.
print(f"{'{text}'} — {'{author}'}")
Итого: сначала браузер прокручивает страницу вниз, чтобы загрузились все цитаты. Затем мы идём по списку всех цитат и выводим их текст, прокручивая к каждой цитате для визуального эффекта. Отката вверх автоматически не происходит.
Для более живого эффекта можно выводить текст прямо во время скролла, как будто пользователь листает страницу и видит новые цитаты сразу.
Используя Selenium с ожиданиями и скроллом, вы можете парсить динамический контент и получать полные данные с сайтов, которые активно используют AJAX.
Больше уроков по парсингу на parsertools.ru/lessons.
