Многие начинающие разработчики сталкиваются с задачей, где нужно получить данные с сайта, а открытого API у него нет или его использование по каким-либо причинам невыгодно.

Самый очевидный из вариантов — парсинг HTML, но здесь часто возникает проблема: часть данных подгружается через JavaScript. В такие моменты использование условного requests и BeautifulSoup бесполезно.

Здесь на помощь приходит Selenium — инструмент для автоматизации браузера. С его помощью можно открывать страницы, имитируя действия настоящего пользователя, выполнять JavaScript и забирать данные в правильном виде.

Это простыми словами. Если говорить корректнее, Selenium WebDriver (более точное название продукта) — программная библиотека, позволяющая управлять браузером. Это огромное «семейство» драйверов для разных браузеров и набор библиотек для драйверов. Cамое важное: это не браузер, а библиотека, которая работает с браузером.

А чтобы такой браузер не пожирал ресурсы, мы будем использовать безголовый режим (headless). Это значит, что браузер работает «невидимо» — без графического интерфейса, но со всеми возможностями настоящего браузера.

Итак, в этой статье мы разберём:

  • Что такое headless-браузеры и зачем они нужны;

  • Какие приёмы помогут избежать бана и ошибок;

  • Как настроить Selenium для парсинга.

  • И как все это развернуть на облаке Amvera, чтобы парсер работал 24/7 и не ловил 429.

Теоретическая часть

Будем двигаться по плану.

Чуть ранее я кратко рассказал, что такое безголовый браузер, сейчас же затронем тему чуть глубже.

Headless-режим

Обычно, когда мы запускаем Selenium, открывается полноценное окно браузера: видно вкладку, интерфейс, как будто вы сами сидите за компьютером и кликаете по кнопкам. Это удобно для отладки — сразу понятно, что происходит, в чём ошибка и подобное.

Но для реальной работы парсера такое поведение неудобно:

  • браузер занимает много ресурсов (GPU, память, процессор);

  • окно мешает, если запускать парсер на сервере;

  • невозможно работать на headless-сервере (например, в облаке), где просто нет графической оболочки.

Здесь и нужен headless-режим (от английского headless — "без головы").
Это специальный режим работы браузера, при котором он не отображает графический интерфейс, но выполняет все те же действия:

  • загружает страницы,

  • выполняет JavaScript,

  • открывает всплывающие окна и iframes,

  • может делать скриншоты и сохранять HTML.

То есть разница только в том, что у браузера “нет головы” — картинки вы не видите, но внутри он все так же работает.

Как избежать бана

Парсер - это всегда взаимодействие с чужим сервисом. Чтобы это взаимодействие было стабильным и не привело к блокировке, придерживайтесь двух принципов:

  1. Имитируйте поведение реального пользователя: делайте паузы, прокрутки, клики.

  2. Не нагружайте сайт излишним количеством запросов. Используйте кеширование, бекоффы.

Об этом рассказали больше в нашей прошлой статье про универсальный парсинг.

Однако хочется выделить наверное одно из главных преимуществ облака Amvera для нашей задачи, на котором мы развернем тестовый проект: ротация исходящих IP из пула. Это нам сильно поможет избежать большинства блокировок IP и 429 (Too Many Requests), т.к. запросы попросту будут идти с разных IP.

Расскажу подробнее.

Почему Amvera

Amvera особенно удобный сервис для нашей задачи и деплоя в целом:

  • Автоматический пул IP. Как я уже говорил ранее: запросы распределяются через разные адреса, что снижает вероятность блокировок и появления ошибки 429 Too Many Requests. Все это работает из коробки и бесплатно.

  • Возможность запускать задачи в режиме Cron Jobs, оплачивая только минуты работы парсера. Это дешевле, чем использование постоянно работающей VPS. Функциональность находится в режиме теста и будет доступна всем пользователям с 10 октября 2025.

  • Простое развертывание. Все, что нужно — задать несколько параметров и выполнить 4 команды через git push. При этом есть и веб-интерфейс, если не хочется работать из терминала. Начать можно ,бесплатно, используя приветственный баланс в 111 р.

Теперь перейдем к практике.

Практическая часть: первый парсер на Selenium

1. Установка Selenium и драйвера

Для начала установим библиотеку Selenium:

pip install selenium

Selenium, как мы выяснили ранее, управляет браузером через WebDriver — отдельный драйвер для каждого браузера.

Для примера возьмём Chrome:

2. Настройка headless-браузера

Чтобы браузер не открывался визуально, используем headless-режим. Пример для Chrome:

from selenium import webdriver
from selenium.webdriver.chrome.options import Options

options = Options()
options.add_argument("--headless")  # Тот самый headless режим. Можно использовать "--headless=new"
options.add_argument("--disable-gpu")  # Отключаем GPU для стабильности
options.add_argument("--no-sandbox")  # Нужно для Linux
options.add_argument("--window-size=1920,1080")  # Размер окна

driver = webdriver.Chrome(options=options)  # Если нужно - указываем путь к браузеру

Эти параметры позволят браузеру работать невидимо.

3. Открытие страницы и базовые действия

Простейший пример: открыть страницу и получить заголовок:

... весь прошлый код

driver.get("https://example.com")
print(driver.title)  # Выведет заголовок страницы ("Example Domain")

Навигация по элементам:

from selenium.webdriver.common.by import By

# Найти элемент h1
element = driver.find_element(By.CSS_SELECTOR, "h1")
print(element.text)

# Найти элемент по ID
element = driver.find_element(By.ID, "main")

Взаимодействие с элементами:

# Клик по кнопке
button = driver.find_element(By.CSS_SELECTOR, ".btn")
button.click()

# Ввод текста в поле
input_box = driver.find_element(By.NAME, "q")
input_box.send_keys("Selenium парсер")
input_box.submit()  # Отправка формы

4. Ожидания (для избежания ошибок)

Многие сайты подгружают данные через JavaScript, поэтому Selenium игрока не успевает найти элементы. Поэтому используем ожидание:

from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

# Ждем до 10 секунд пока элемент .card не появится
element = WebDriverWait(driver, 10).until(
    EC.presence_of_element_located((By.CSS_SELECTOR, ".card"))
)
print(element.text)

5. Получение HTML и скриншотов

# Получаем весь HTML страницы
html = driver.page_source Три раза прокручиваем страницу каждую секунду

# Скриншот страницы
driver.save_screenshot("screenshot.png")

6. Закрытие браузера

После работы важно закрывать браузер:

driver.quit()

7. Установка User-Agent

Чтобы парсер не был легко вычислим, нужно задать User-Agent. Лучше всего использовать fake-useragent, который рандомно прокинет нам UA.

# pip install fake-useragent

from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.chrome.options import Options
from webdriver_manager.chrome import ChromeDriverManager
from fake_useragent import UserAgent

ua = UserAgent()
user_agent = ua.random

options = Options()
options.add_argument("--headless=new")
options.add_argument("--disable-gpu")
options.add_argument("--no-sandbox")
options.add_argument("--window-size=1920,1080")
options.add_argument(f"user-agent={user_agent}")

8. Автоматическая установка ChromeDriver

Вместе ручной установки браузера мы можем использовать библиотеку, которая сама установит и прокинет путь до ChromeDriver — webdriver-manager.

Сначала установим библиотеку:

pip install webdriver-manager

Пример с Selenium и fake-useragent:

from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.chrome.options import Options
from webdriver_manager.chrome import ChromeDriverManager
from fake_useragent import UserAgent

# Рандомный User-Agent
ua = UserAgent()
user_agent = ua.random

# Настройка опций Chrome
options = Options()
options.add_argument("--headless=new")
options.add_argument("--disable-gpu")
options.add_argument("--no-sandbox")
options.add_argument("--window-size=1920,1080")
options.add_argument(f"user-agent={user_agent}")

# Автоматическая установка ChromeDriver
service = Service(ChromeDriverManager().install())
driver = webdriver.Chrome(service=service, options=options)

# Пример работы
driver.get("https://example.com")
print("Заголовок страницы:", driver.title)

driver.quit()

9. Прокрутка контента

Многие сайты прогружают контект динамически при скролле. Поэтому иногда приходится делать полный строк страницы:

# Прокрутка страницы вниз до конца
driver.execute_script("window.scrollTo(0, document.body.scrollHeight);")

Или по шагам с паузой:

import time

for i in range(3):
    driver.execute_script("window.scrollBy(0, 1000);")
    time.sleep(1)  # ждём подгрузки контента

10. Мини-проект парсера сайта

Можно сразу собрать простой скрипт, который:

  1. Открывает сайт example.com

  2. Находит заголовок страницы и выводит его.

  3. Сохраняет скриншот страницы.

from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.common.by import By

from webdriver_manager.chrome import ChromeDriverManager
from fake_useragent import UserAgent

options = Options()
options.add_argument("--headless=new")
options.add_argument("--disable-gpu")
options.add_argument("--no-sandbox")
options.add_argument("--window-size=1920,1080")

service = Service(ChromeDriverManager().install())
driver = webdriver.Chrome(service=service, options=options)
driver.get("https://example.com")

title = driver.find_element(By.TAG_NAME, "h1").text
print("Заголовок страницы:", title)

driver.save_screenshot("example.png")
driver.quit()

Это минимально рабочий парсер. Его можно расширять: искать списки, собирать текст, кликать по вкладкам, прокручивать страницы, добавлять UA для правдоподобности и так далее.

Деплой парсера

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

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

Сразу после подтверждений у вас будет доступно 111 рублей для первого запуска и тестов.

Создание проекта

После регистрации мы можем перейти к созданию проекта: перейдем в ЛК и нажмем кнопку «Создать проект» c типом «Приложение».

Переходим на страницу проекта.

Загрузка данных

Прежде чем загрузить данные, давайте подготовим Dockerfile.

Dockerfile - файл с инструкциями для сборки и запуска нашего проекта. В нем мы пропишем конкретные команды, которые будут выполнены на стадии сборки.

Вот содержимое Dockerfile для нашей задачи:

FROM  python:3.11

WORKDIR /app

# устанавливаем google-chrome
RUN wget https://dl.google.com/linux/direct/google-chrome-stable\\_current\\_amd64.deb
RUN apt-get update && apt-get install -y ./google-chrome-stable_current_amd64.deb

# выставляем нужный порт дисплея
ENV  DISPLAY=:99

COPY . ./

RUN pip install -r requirements.txt
Он
CMD ["python", "main.py"]

Здесь у нас указаны два файла:

  • main.py - скрипт, в котором мы прописали основную логику запуска парсера,

  • requirements.txt - файл, в котором содержатся названия и версии библиотек, которые используются в нашем проекте.

В случае минимально рабочего парсера, указанного в 10 пункте теоретической части, requirements.txt будет выглядеть так:

selenium==4.35.0
fake-useragent==2.2.0
webdriver-manager==4.0.2

Теперь можем загружать все три файла: main.py, Dockerfile, requirements.txt.

Конфигурация

Прежде чем собрать и запустить проект желательно создать файл конфигурации. Но он не обязателен, если в корне есть Dockerfile - это мы можем пропустить и сразу во вкладке "Конфигурация" нажать кнопку "Собрать".

После всей действий проект должен корректно собраться и запуститься.

Итог

В статье мы разобрали, как настроить Selenium для парсинга, узнали про healess-браузеры и разобрали базовые действия.

Этого достаточно для старта, но важно понимать, что для реальных проектов рекомендуется:

  • Добавлять обработку ошибок и повторные попытки при падении;

  • Внедрять логирование и хранение HTML для отладки;

  • Более серьёзно защищаться от детекта частых запросов с ошибкой 429.

После адаптаций под вашу задачу, парсер сможет стать надёжным инструментом.

Комментарии (17)


  1. NikitinIlya
    28.09.2025 08:51

    Многие сайты используют каптчу. Как быть с парсингом в этом случае большой вопрос.


    1. yoigo
      28.09.2025 08:51

      Решить самим капчу или просить провайдер чтоб за вас это сделал за $.

      Есть библиотеки которые делают это за вас, например решить капчу амазон.


  1. DjUmnik
    28.09.2025 08:51

    Имхо, Camoufox для особо сопротивляющихся сайтов лучше.


    1. yoigo
      28.09.2025 08:51

      Согласен, мы как раз его и используем!


    1. nikulin_krd
      28.09.2025 08:51

      Только он до сих пор в бете и у него в мердж реквестах до сих пор висят патчи на антидетект


  1. DEJourneyman
    28.09.2025 08:51

    Для меня как начинающего специалиста этот туториал находка, большое спасибо.


    1. barraqud
      28.09.2025 08:51

      Если интересна эта тема, то обратите внимание на статьи от Zenrows(и конкурентов) там много полезного, а для самопроверки на детект и утечки можно пробежаться по https://github.com/TheGP/untidetect-tools?tab=readme-ov-file


  1. Emelian
    28.09.2025 08:51

    Парсинг сайтов с Selenium на Python

    Selenium –это большой проект и для его использования нужны большие основания. У меня задача была попроще – скачать несколько онлайн-словарей для самообразования. Для одного из них хватило простого Питона (без сложных библиотек), а для остальных старой версии Хром (версия 109), для того, чтобы сохранить возможность работы со второй версией манифеста. Поскольку, в последних выпусках Хрома доступен только третий манифест (насколько я знаю), а он уже имеет ограничения в работе, которых не было во втором манифесте. Это касается и блокировщика рекламы сайтов и работы с файлами. А Хром нужен для (ручного) обхода капчи – «дешево и сердито».

    Другим словами, нужно было «ехать», а не «шашечки». И если эту задачу решает «велосипед», то зачем тогда нужен «мерседес?

    Теперь, тоже самое, но чуть подробнее.

    Я, без особых проблем, скачивал онлайн-словари и mp3-файлы к ним на десятки тысяч слов, используя собственное расширение Хром. Правда, приходилось выставлять паузу – пять секунд, между запросами, зато, вэпээн-ом пользовался редко. Полученные html-страницы, естественно, пришлось конвертировать в более удобоваримый вид (в конечном счете – текстовый), но, в итоге, нужные мне данные я получил.

    Если говорить не «вообще», а «конкретно», то вполне можно использовать веб-скрапинг с помощью расширений на старых версиях Хрома, все еще поддерживающих вторую версию манифеста.

    При этом, начальную капчу можно проходить вручную, потом это дает нам какое-то количество времени (обычно, минут 5 – 30) до появления следующей капчи. Во время этого интервала мы запускаем свой небольшой скрипт расширения, который с небольшой задержкой, скажем, секунд пять, делает запросы на загрузку необходимых html-страниц, которые мы просто тупо сохраняем в своем каталоге. Их обработкой мы можем заняться потом, когда уже всё скачаем, Это может быть и сотня тысяч страниц.

    При этом, в процессе скачивания страниц мы можем отследить начало сбоя. В Хроме это хорошо видно. Останавливаем скрипт, переинициализируем его, при необходимости, снова вручную набираем соответствующий url в Хроме, опять проходим капчу (при подозрении сервера, он может запрашивать ее несколько раз). Для профилактики подозрений, периодически меняем ай-пи, например, посредством вэпээна.

    Скриптом расширения, хотя там всего пара десятков строчек, делиться не буду, чтобы не палиться. Раньше я использовал скрипты Питона для аналогичных целей, пока не столкнулся с капчей. С ней возникли проблемы, пока не нашел в Интернете подходящий прототип расширения на базе второй версии манифеста (как я уже говорил, современный Хром поддерживает только третью, значительно урезанную в своих возможностях). Слегка доделал его «напильником» и вуаля…

    В итоге, загрузил два разных сайта, порядка ста тысяч страниц. На каждый ушло по месяцу, примерно. Сайты крутили время доступа, между капчами, от 5 до 30 минут, потом обратно. Это несколько напрягало, но, параллельно, занимался другой работой, да и спешить мне было особо некуда.

    Сначала увлекался, задержки между запросами были нулевые и сайты мои вэпээны быстро банили. Но всегда их «хавали» при ротации. Допускаю, что, сервера слишком надеялись на свои капчи и другие способы защиты особо не использовали, хотя, я постоянно ждал подвоха с их стороны.

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

    Таким образом, на универсальность не претендую, но свои личные проблемы решил. Более того, все данные корректны, я их полностью обработал и проверил. А вот, когда работал с подобными скриптами на Питоне, без капч, то, да, за ними нужен был глаз да глаз. Данные отгружали всегда, но после небольшого объема корректных данных начинали поступать некорректные. Да и задержку между запросами там нужно было выставлять секунд пятнадцать, не меньше, ибо очень подозрительные сервера были. Зато особо не придирались к ай-пи, можно было работать без вэпээна. Короче говоря, везде использовал специфику частных случаев…


  1. TerryChan2003
    28.09.2025 08:51

    Щас бы селениум в 2к25, как же плейврайт? Чем хуже селенума?


    1. nikulin_krd
      28.09.2025 08:51

      Он как раз лучше)) А локаторы у него это просто сказка - позволяют кучу рутины убрать


  1. andreymal
    28.09.2025 08:51

    часть данных подгружается через JavaScript. В такие моменты использование условного requests и BeautifulSoup бесполезно.

    Разумеется, ничего не мешает подгружать данные через тот же requests точно так же, как это делает JavaScript, без всяких селениумов и плейврайтов


  1. northrop
    28.09.2025 08:51

    Пробую запустить такой скрипт

    options = webdriver.ChromeOptions()
    options.add_argument("--start-maximized") # Open browser maximized
    options.add_argument('--no-sandbox')
    options.add_argument('--disable-dev-shm-usage')
    options.add_argument("--user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:140.0) Gecko/20100101 Firefox/140.0")
    options.add_argument("--headless") # Run in background (no GUI)
    options.add_experimental_option("detach", True)

    drv = webdriver.Chrome(service=Service(ChromeDriverManager(driver_version="latest").install()), options=options)

    И оно падает, неся какую-то хрень - https://pastebin.com/3WjwBhdT
    При этом , на машине есть и FF 140.3.0esr (32-bit), и хром 140.0.7339.208 (Official Build) (64-bit). Что я делаю не так?


    1. nikulin_krd
      28.09.2025 08:51

      Что вы делаете не так? Вы не читаете документацию


    1. northrop
      28.09.2025 08:51

      И какаую именно, можно поподробнее? К тому же, есть 2 машины, на обоих Win10 22H2 + Python 3. На одной этот скрипт запускается и не падает, а на второй падает. Набор броузеров там по версиям +- последняя цифра релиза совпадает. Так в чем же проблема там, где падает?


  1. w00dLAN
    28.09.2025 08:51

    А можно запускать selenium на сервере?

    Кидаю ссылку на сайт в бот, тот на сервере запускает скрапинг и возвращает txt файл.

    Реализуемо такое на "безмониторных" системах типа серверной Ubuntu?


    1. MarkovM Автор
      28.09.2025 08:51

      Да, не вижу сложностей, только если каптчу не нужно проходить.


  1. CrazyPolotenchik
    28.09.2025 08:51

    Ох, я помню продолбался пока делал парсер на авито) но вопрос с капчей так и не решил.