Пример парсинга сайта на Python + Selenium: достаем информацию эффективно

Или как парсить сайты «по-человечески». Но все по порядку.
Представим такую ситуацию. Вы занимаетесь парсингом на python: отсылаете запросы с помощью библиотеки requests, достаете информацию с BeautifulSoup4. И раньше все получалось хорошо, но тут задача тяжелее - на странице есть разные select-box’ы, check-box’ы, динамическая подгрузка данных. С такой задачей requests не справится.
Дело в том, что requests подходит для парсинга статических данных: отправил запрос, сразу получил всю информацию и делай что хочешь. А когда нужны какие-то действия, то эта библиотека бессильна.
Что делать?
Использовать Selenium - мощную и гибкую технологию. С ней вы не просто отправляете запрос, а имитируете настоящего человека. Заполняете формы, нажимаете на кнопки, скролите страницы, двигаете мышью. А еще эта технология поддерживает разные языки программирования. Мы будем писать на Python и использовать ОС Windows.
Переходим к практике.
Установка
Selenium дает возможность использовать разные браузеры как основу, но мы остановимся на Chrome. Убедитесь, что у вас установлен браузер и сам Python или другой язык.
Открываем директорию с нашими проектами в командной строке, создаем директорию проекта и переходим в нее:
mkdir first_selenium && cd first_selenium
Дальше создаем виртуальное окружение, активируем его:
python -m venv venv && venv\Scripts\activate
Наконец, устанавливаем Selenium:
pip install selenium
Подготавливаемся к работе
Открываем созданный проект в любимом редакторе (я использую PyCharm) и создаем файл create_driver.py
- в нем будет функция создания драйвера, которую и будем вызывать. Таких настроек будет достаточно:
from selenium import webdriver
def create_driver(url):
options = webdriver.ChromeOptions()
options.add_argument("start-maximized")
options.add_argument("--headless") # работа без открытия окна браузера
options.add_argument(
"user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) "
"Chrome/105.0.0.0 Safari/537.36")
options.add_argument("--disable-blink-features=AutomationControlled")
driver = webdriver.Chrome(options=options)
driver.get(url)
return driver # возвращаем драйвер
Ну и куда без main.py
- создаем его, выполняем импорты и не забываем про функцию для создания драйвера.
from selenium.webdriver.common.by import By
from create_driver import create_driver
Начинаем парсить
Давайте попробуем получить ссылки на все статьи на нашем сайте. Если вы умеете парсить на requests, то и в HTML разбираетесь. Если нет, то потребуется знание основ языка разметки. Какие есть блоки, что такое классы, айди и так далее.
Открываем главную страницу - https://itkitchen.space/, прожимаем Ctrl+U или жмем правой кнопкой мыши на экран и далее «Просмотр кода страницы». Вот что у нас открывается:

Это - весь HTML-код, представленный на странице. Теперь наша задача - найти ссылки на каждую статью. Что мы делаем? Находим на главной странице название любой статьи и далее ищем его в HTML-коде через Ctrl+F.

Нас интересует <a class="post-title-link" href="/time-complexity/"></a>
. Так мы узнали, что ссылка на статью находится в атрибуте href
элемента <a>
с классом post-title-link
. Все, что нам остается - пройтись по всему коду и взять эти самые ссылки. Добавляем в main.py
:
url = "https://itkitchen.space/"
driver = create_driver(url) # создаем драйвер
all_links = driver.find_elements(By.CLASS_NAME, "post-title-link") # получаем все элементы с классом post-title-link
hrefs = [] # пока пустой массив для самих ссылок
for link in all_links:
hrefs.append(link.get_attribute("href")) # получаем у каждой ссылки атрибут href
print(hrefs)
print(len(hrefs))
Мы создали драйвер, передав ему URL главной страницы. Далее используем метод find_elements
с параметрами By.CLASS_NAME
(чтобы находить элементы по их классу) и post-title-link
- само название класса.
By.ID
), названию тега (By.TAG_NAME
) и другим селекторам. Пишите By.
и смотрите, что подходит конкретно в вашей задаче.post title name
, то Selenium выдаст ошибку. Для избежания мы должны соединить все классы через точку и получить post.title.name
- ошибки уже не будет. Идем дальше.Выполняем код, немного ждем и в консоли получаем массив ссылок, а также их количество. На момент написания статьи нам выдало 20, но это как-то мало. Давайте опустимся в низ главной страницы.

И в этот момент мы понимаем, как же полезен Selenium. Статей-то больше, но на сайте присутствует пагинация (про что я и писал в начале - не вся информация загружается сразу). Не будь у нас такой технологии, мы бы копировали ссылки на каждую отдельную страницу, сохраняли их и шли циклом по ним. Мало того, что так делать ну совсем не правильно (мы программируем, работаем головой, а не руками; таким образом мы могли бы и вручную пособирать все статьи), так и оставшиеся статьи могут быть не на отдельной странице, а просто подгружаться. Что тогда делать? То же, что и в начале - находим в коде кнопку перехода на следующую страницу.

Что мы видим? Кнопка на новую страницу есть, но у нее нет класса или идентификатора. Тогда берем чуть выше, там располагается блок <div>
с классом pagination-right
, а уже в нем нужная нам ссылка. Давайте откроем вторую страницу, и на ней видим ту же самую разметку.
Теперь наша логика такая: изначально собираем все ссылки, как мы это уже сделали, но в конце мы пробуем найти кнопку перехода на следующую страницу. Если она есть - нажимаем на нее и делаем то же самое уже на новой странице, если такой кнопки нет – значит, мы все пропарсили. Для наглядности того, как наш браузер будет вести себя «по-человечески» (как я и обещал в заголовке статьи), включим открытие окна браузера в create_driver.py
:
# options.add_argument("--headless") # работа без открытия окна браузера
Идем писать код все в том же main.py
, и вот как он теперь выглядит:
from selenium.webdriver.common.by import By
from create_driver import create_driver
from selenium.common.exceptions import NoSuchElementException
url = "https://itkitchen.space/"
driver = create_driver(url) # создаем драйвер
hrefs = []
# с помощью этой функции мы собираем все ссылки
def get_links():
all_links = driver.find_elements(By.CLASS_NAME, "post-title-link") # получаем все элементы с классом post-title-link
for link in all_links:
hrefs.append(link.get_attribute("href")) # получаем у каждой ссылки атрибут href
get_links() # просто собираем все ссылки на главной странице
while True: # запускаем цикл, который ищет кнопку пагинации
try: # если кнопка нашлась, то мы нажимаем на нее и собираем новые ссылки
div_with_link = driver.find_element(By.CLASS_NAME, "pagination-right") # находим родительский блок ссылки
button_link = div_with_link.find_element(By.TAG_NAME, "a") # находим уже нужную нам ссылку по ее тегу
button_link.click() # нажимаем на нее
get_links()
except NoSuchElementException: # если кнопка не нашлась, перехватываем ошибку и пишем о конце парсинга
print("Парсинг закончился")
driver.quit() # закрываем драйвер
break # прерываем бесконечный цикл
print(hrefs)
print(len(hrefs))
В коде много комментариев, поэтому нет смысла заострять внимание на каком-то моменте. Давайте лучше запустим код и посмотрим на результат.

Все, как и планировали: в какой-то момент кнопки пагинации не нашлось, и поэтому работа скрипта остановилась.
Но давайте добавим немного красоты. В самом верху импортируем модуль time
.
import time
Затем откроем последнюю ссылку:
driver = create_driver(hrefs[-1])
time.sleep(10)
И видим мы первый пост на нашем сайте:

Еще мы видим и плашку вверху, которая показывает нам, что запущено автоматизированное ПО.
Вуаля!
Заключение
Мы познакомились с интересной технологией, не сильно вдаваясь в теорию. Находили элементы и по классу, и по тегу, собрали некоторые данные, и сделали то, для чего и нужен Selenium - понажимали на кнопки и посмотрели на то, с чего все началось ♥
Конечно, Selenium - это не просто собрать ссылки. Его возможности позволяют проверять работу вебсайтов, тестировать сценарии поведения реального человека на странице. Мы можем сохранять сессии, проходить авторизацию на сайте, даже запускать драйвер из собственного браузера и менять размеры окна браузера.
Но с описанием всех этих возможностей статья растянется на полотна. В Интернете много информации, придумывайте или находите сложные задачи и интересуйтесь, как их решить!
Материал подготовлен с ❤️ редакцией Кухни IT.