
При веб парсинге сайтов рано или поздно приходится сталкиваться с механизмами защиты от ботов. Сайты могут блокировать массовые запросы по IP-адресу, выдавать сложные капчи или применять другие антибот меры. Я хочу рассмотреть как реализовать на Python парсинг сайта с обходом таких защит:

Вариантов на самом деле не так много, без сложной и глубокой разработки вы можете обойти антибот меры за счет двух способов:
Использование и ротация прокси-серверов для маскировки запросов.
Распознавание и обход капчи с помощью сервисов вроде 2Captcha и SolveCaptcha.
Парсинг веб-страниц и блокировки: только ли капча блокирует доступ к данным?
Парсинг - это процесс автоматического извлечения данных с веб-сайтов. Обычно для этого на Python используют библиотеки вроде requests (для HTTP-запросов) и парсеры HTML (например, BeautifulSoup). Однако простого кода на requests недостаточно, если сайт активно защищается от ботов. Чаще всего возникают две проблемы:
Блокировки по IP: Если с одного адреса идет слишком много запросов, сайт может временно заблокировать этот IP. Симптомы - внезапные ошибки вроде 429 Too Many Requests или перенаправление на страницу с проверкой.
CAPTCHA: Сайт может потребовать пройти капчу, чтобы убедиться, что вы не бот. Это может проявляться в виде всплывающей проверки "I'm not a robot", страницы с искаженным текстом для ввода, либо других интерактивных задач.
Как правило, это самые распространенные варианты защиту, которые мне доводилось встречать на своей практике. Есть еще отдача пустых страниц, и когда парсер молотит вхолостую какое то время и через определенный период у тебя нулевые результаты. В общем, давайте по порядку попробуем разобраться, как избежать подобных ошибок на практике.
Ротация прокси при парсинге - альтернатива распознаванию капчи
Зачем нужны прокси? При массовых запросах к сайту важна маскировка источника трафика. Запросы, идущие с одного IP-адреса, быстро распознаются как автоматизированные и блокируются. Использование пула прокси-серверов позволяет менять IP-адрес при каждом запросе, снижая шансы блокировки. В современном парсинге работать без прокси - моветон (особенно при большом потоке запросов).
Выбор прокси: Можно использовать бесплатные открытые прокси, но они часто ненадежны и медленные (бывают конечно исключения, но необходимо сильно постараться, и как говориться - еще и места знать нужно). Для серьезных проектов я рекомендую брать платные прокси (серверные, резидентные, мобильные) - они быстрее, стабильнее и уверенности в том, что вас не заблокируют по причине плохого IP адреса меньше.

Как это реализуется на Python
Библиотека requests поддерживает работу через прокси. Достаточно передать параметр proxies со словарем вида {"http": "...", "https": "..."}. Чтобы автоматически менять прокси на каждую итерацию, удобно использовать список прокси и цикл. Пример:
import requests
import itertools
# Список прокси: поддерживаются http/https/socks5, с авторизацией или без
proxy_list = [
{"http": "http://111.222.333.444:8080", "https": "http://111.222.333.444:8080"},
{"http": "http://user:pass@555.666.777.888:3128", "https": "http://user:pass@555.666.777.888:3128"},
# {"http": "socks5://127.0.0.1:9050", "https": "socks5://127.0.0.1:9050"}, # пример SOCKS5
]
# Циклический итератор по списку прокси
proxy_cycle = itertools.cycle(proxy_list)
url = "http://httpbin.org/ip"
for i in range(3):
proxy = next(proxy_cycle)
try:
resp = requests.get(url, proxies=proxy, timeout=(5, 10))
print(f"Request {i+1} via {proxy['http']} -> {resp.json()}")
except requests.RequestException as e:
print(f"Request {i+1} via {proxy['http']} failed: {e}")
В этом коде мы делаем 3 запроса, каждый раз беря следующий прокси из списка (с помощью itertools.cycle, который зациклит список при необходимости). На практике список прокси быстро "выгорает": часть перестает работать, часть блокируется. Поэтому обычно реализуют проверку доступности или используют сервисы с автоматической ротацией IP
После внедрения прокси парсер становится менее заметным, но полностью проблему блокировок это не решает. Прокси помогут снизить частоту появлений капчи (например, Google reCAPTCHA часто возникает при подозрительном трафике с одного IP), но все равно сложные сайты могут выдать капчу даже при редких запросах.
Виды CAPTCHA и почему их трудно обходить через сервисы распознавания капчи
CAPTCHA (Completely Automated Public Turing test to tell Computers and Humans Apart - полностью автоматизированный публичный тест Тьюринга для распознавания компьютеров и людей) бывают разных типов, если интересно подробнее погрузиться в тематику видов капч, у меня есть на эту тему статья - какие виды капчи бывают и как их обходить. Вот основные виды, с которыми вы можете столкнуться, и их особенности:

Классическая текстовая CAPTCHA. Искаженный текст или числа в картинке, которые нужно правильно ввести. Это может быть набор кривых символов на шумном фоне и т.п.. Такие капчи придуманы так, чтобы людям было относительно легко разглядеть буквы, а программам - сложно. Формально их можно решать алгоритмами OCR (оптического распознавания символов), но современные варианты часто слишком сложны для простого OCR.
Google reCAPTCHA v2. Распространённый вид капчи от Google. Может проявляться как флажок "I'm not a robot" (простая проверка, которая по клику анализирует поведение пользователя) либо как полноценный тест с выбором изображений по заданию (например, "выберите все картинки со светофорами"). Также reCAPTCHA v2 имеет невидимый режим - капча не показывается, но анализирует поведение пользователя на странице и может потребовать решение только при подозрительной активности.
hCaptcha и FunCaptcha (Arkose Labs). Альтернативные капчи, похожие по идее на reCAPTCHA, но от других компаний. hCaptcha часто используется Cloudflare и другими сервисами: показывает картинки с задачами (найти объекты и т.п.). FunCaptcha (Arkose) - интерактивные задания (например, вращать объект, собрать пазл и т.д.). Каждая из этих систем имеет свои нюансы реализации, и они регулярно усложняются.
Другие виды. В последнее время чаще встречаются GeeTest (популярна в Азии, характерна движущимся слайдером-пазлом), капчи с перестановкой изображений, аудио-капчи для слабовидящих (воспроизведение чисел или слов, которые нужно ввести), простые математические задачи, слайдеры и др..
В общем, вариантов много, и универсального решения под все не существует - под каждый тип капчи нужен свой подход.
Подходы к распознаванию капчи
Собственно для борьбы с капчей пока придумано 2 варианта, и один из них я уже выше затронул по касательной:
Предотвращение появления капчи. Идеальный сценарий - настроить парсер так, чтобы капча вообще не появлялась. Это означает действовать максимально "по-человечески", избегая ее появления настолько, насколько это может быть возможным:
Медленнее слать запросы, не долбить сайт сотнями запросов в секунду.
Ротировать IP адреса.
Менять User-Agent у запросов, имитируя разные браузеры.
Использовать небольшие рандомные задержки, не повторять точно одни и те же пути по сайту.
Учитывать robots.txt (не лезть на запрещенные разделы).
Сохранять cookies между запросами, чтобы выглядеть как последовательные визиты одного пользователя, а не новые сессии каждый раз.

Перечисленные методы снижают вероятность спровоцировать антибот защиту. Однако полностью избежать капчи не всегда возможно - особенно на сильно защищённых платформах или при очень больших объемах данных. Поэтому всегда нужен план B.
Автоматическое решение капчи. Если капча все-таки возникла - скрипт должен суметь ее решить. Самый практичный подход - отправить капчу на специальный внешний сервис, который ее решит и вернёт ответ. Современные антикапча-сервисы совмещают нейросети (OCR) и людей: простые капчи решаются алгоритмом за секунды, сложные передаются на ручной ввод работникам, чтобы гарантировать результат. Например, сервис распознавания капчи 2Captcha уже много лет привлекает распределенную команду людей по всему миру для расшифровки капч за небольшую плату. Сервис SolveCaptcha делает ставку на гибрид ИИ + человек: простые текстовые капчи решает нейросеть за 2-5 секунд, а сложные сразу отдает людям (либо пробует решить их нейросетью и в случае неудачи, передает на решение человеку). Такой подход позволяет решить практически любую капчу - вопрос только во времени (от пары секунд до ~20 секунд) и небольших затратах за каждое решение.
Важное уточнение! Автоматическое распознавание капчи - это дополнительное время и деньги. Капча решается запросом на сторонний API и часто занимает несколько секунд, замедляя парсер. Поэтому лучше избегать появления капчи, а к решению прибегать как к запасному плану. Давайте рассмотрим варианты, как именно решать разные виды капчи с помощью Python.
Распознавание классических текстовых капч (изображения с текстом)
Суть проблемы: Вам дана картинка с искаженными символами, и нужно программно определить, какие там буквы/цифры. Варианты решений:
Попробовать использовать OCR-библиотеки (например, Tesseract через pytesseract). Простой OCR может справиться с очень лёгкими капчами, но на практике сложные искажения и шум делают этот путь ненадежным без серьёзного обучения модели.
Воспользоваться антикапча-сервисом: отослать изображение и получить текст оттуда. Сервисы 2Captcha/SolveCaptcha такие задачи решают быстро либо алгоритмом, либо человеком.
Библиотеки: Сервис 2Captcha предоставляет официальный Python-модуль 2captcha-python, облегчающий интеграцию. У SolveCaptcha есть аналогичный модуль solvecaptcha-python. Оба модуля берут на вход файл или base64-строку изображения и возвращают распознанный текст. Установить их можно через pip:
pip install 2captcha-python solvecaptcha-python
Если решать через модуль 2Captcha простую капчу с текстом. Нужно передать файл "captcha.jpg" с изображением капчи. Код будет таким:
from twocaptcha import TwoCaptcha
solver = TwoCaptcha('ВАШ_API_KEY_2CAPTCHA') # ключ API берём из аккаунта 2Captcha
result = solver.normal('captcha.jpg') # можно передать путь к файлу
print("Распознанный текст:", result['code'])
Соответственно, сперва нужно сохранить или получить изображение капчи. В случае статического URL картинки можно скачать через requests. Если капча генерируется динамически (например, внутри браузера), может понадобиться Selenium, чтобы сделать скриншот элемента. Методика максимально простая - делаете скрин, конвертируете его в base64 и отправляете на сервис решения капчи, после получения ответа - подставляем готовое решение и идем дальше.
Для SolveCaptcha код будет похожим, только нужно использовать их библиотеку и API-ключ:
from solvecaptcha import SolveCaptcha
solver = SolveCaptcha('ВАШ_API_KEY_SOLVECAPTCHA')
result = solver.image('captcha.jpg') # условный метод для простой капчи
print("Распознанный текст:", result['code'])
Обычно сервисы сами определяют тип капчи по содержимому: передавая просто файл картинки, мы получим текстовый результат. Важный нюанс - ограничения по времени. Сервисы стараются решить капчу в пределах 20-60 секунд по умолчанию. В коде можно настроить таймаут ожидания (в TwoCaptcha(..., defaultTimeout=70)). Если капча не решена за это время (бывает редко), вернется ошибка и можно попробовать повторно.
Как обойти reCAPTCHA v2 (Google) - практический пример распознавания Рекапчи
Суть проблемы: На сайте интегрирована reCAPTCHA v2 - либо вам нужно поставить галочку "I'm not a robot" и пройти картинки, либо капча невидимо ждет подозрительных действий. Для автоматизации нужно получить специальный токен (g-recaptcha-response), который обычно генерируется виджетом капчи в браузере после успешного решения.

Подход с 2Captcha/SolveCaptcha: Эти сервисы позволяют решить reCAPTCHA v2 с помощью своих работников. Вам не нужно распознавать сами картинки - достаточно отправить публичный ключ сайта (sitekey) и URL страницы на сервис, а он вернёт готовый токен. Принцип такой:
Вы находите на странице HTML элемент reCAPTCHA, обычно это <div class="g-recaptcha" data-sitekey="...">. Достаёте значение data-sitekey - это и есть нужный ключ.
Вызываете метод API антикапча-сервиса, передавая свой API-ключ, тип капчи и параметры:
sitekey - тот самый ключ сайта.
pageurl - URL страницы, на которой капча появляется.
Дополнительно: если это невидимая reCAPTCHA v2, нужно указать параметр invisible=1.
Если требуются прокси - указать параметры прокси.
3. Сервис возвращает ID задачи сразу, а спустя несколько секунд - сам токен-решение. Готовый токен - длинная строка, которую обычно нужно вставить в скрытое поле формы g-recaptcha-response и отправить на сайт.
Эту логику вручную реализовывать сложно, но библиотеки 2Captcha/SolveCaptcha берут часть работы на себя. Например, с TwoCaptcha можно сделать:
result = solver.recaptcha(sitekey="SITE_KEY_ИЗ_СТРАНИЦЫ", url="https://target.site/page")
token = result['code']
print("Получен токен reCAPTCHA:", token)
Внутри библиотека отправит запрос на URL API сервиса. Для 2Captcha это что-то вроде:
POST http://2captcha.com/in.php
key=ВАШ_API_KEY
method=userrecaptcha
googlekey=SITE_KEY
pageurl=https://target.site/page
Сервис вернет ID, после чего библиотека через несколько секунд сделает второй запрос на:
GET http://2captcha.com/res.php?key=ВАШ_API_KEY&action=get&id=ID
и получит либо готовый токен, либо код состояния (например, CAPCHA_NOT_READY если еще не решена). Как только токен получен, скрипт возвращает его. В случае SolveCaptcha API формат схожий - у них даже заявлена совместимость с протоколом 2Captcha, что упрощает переход между сервисами.
Использование прокси при решении reCAPTCHA: Часто для reCAPTCHA важно, с какого IP она решается. Например, Google может сверять, что токен выдан тому же IP, с которого идет запрос на сайт. Если вы шлете запросы через прокси из Германии, а решаете капчу через сервис без прокси (работник с другого конца света) - сайт может не принять токен. Поэтому 2Captcha и другие сервисы дают возможность задать прокси, через который их работник/скрипт будет обращаться к Google. В библиотеке TwoCaptcha это можно указать при решении, либо задать глобально при инициализации. В raw API SolveCaptcha, к примеру, есть поля proxy и proxytype. Пример установки прокси в 2Captcha:
solver = TwoCaptcha(api_key, defaultTimeout=120, proxy={
'type': 'HTTPS',
'uri': 'login:password@123.45.67.89:3128'
})
result = solver.recaptcha(sitekey=..., url=...)
Так ответ от Google reCAPTCHA будет получен с нужного IP. Proxy для решателя должен быть стабильным, иначе решение может не состояться. Если не указать, сервис постарается решить без прокси (подходит для proxyless reCAPTCHA, когда сайт не проверяет IP, или если у сервиса есть свои региональные сервера).

Внедрение токена и завершение проверки: Получив token, нужно финализировать проверку на сайте:
Если вы отправляете форму через requests, убедитесь, что в POST-параметрах есть поле g-recaptcha-response со значением токена. Некоторые сайты дополнительно ожидают определенный callback или AJAX-запрос.
Если вы автоматизируете браузер (Selenium), можно выполнить JavaScript на странице: вставить токен в поле #g-recaptcha-response и вызвать callback. Например, в SolveCaptcha документации советуют вызвать сохранённую функцию:
document.getElementById("g-recaptcha-response").innerHTML="TOKEN"; myCallbackFunction();. Либо найти и отправить форму после вставки токена.
На практике, многие сайты с reCAPTCHA v2 просто проверяют токен на сервере при сабмите формы - достаточно отправить форму с токеном, и если он верный, дальнейший контент станет доступен.
Распознавание reCAPTCHA v3 и распознавание Cloudflare Turnstile капчи
reCAPTCHA v3: тут уже нет явной капчи, но сервер может запросить токен v3. Сервис 2Captcha умеет получать такие токены: вы также передаете sitekey и URL, плюс параметр version=3 и желаемый минимальный балл (0.3, 0.7 и т.д.). Вам вернется токен, который при проверке Google покажет нужный балл (не факт, что максимум 1.0, но обычно сервис старается получить около 0.3-0.7 по умолчанию). Далее этот токен отправляется так же, как в v2, только без пользовательского взаимодействия. Помните: если сайт настроен требовать балл 0.9 (почти как реальный пользователь), то даже полученный токен может не пройти проверку - тут уже помогают либо имитация человеческого поведения для повышения своего реального балла, либо использование браузерных антидетект инструментов.

Cloudflare Turnstile: более сложный аналог reCAPTCHA v3 от Cloudflare (иногда с дополнительными проверками). Она тоже возвращает токен через hidden input cf-turnstile-response. Turnstile поддерживается и 2Captcha, и SolveCaptcha. Вы взаимодействуете схожим образом: отправляете сайт-ключ (похожий на reCAPTCHA sitekey) и адрес, получаете токен. По скорости можно отследить в реальном времени, как быстро идет решение, используем для этого сервис CaptchaTheCat, тут показано, что 2Captcha решает Turnstile за ~11 секунд. То есть сервисы уже адаптировались к ней. Но могут быть проблемы с вызовом, для обхода зачастую применяют специальную инъекцию, но это тема отдельной статьи, оставим ее на потом.
Использование токена Turnstile аналогично - отправляем вместе с остальными данными формы либо через Selenium вставляем и сабмитим форму.
Распознавание hCaptcha и обход FunCaptcha (Arkose Labs)
hCaptcha: визуально напоминает reCAPTCHA (выбор картинок), но от другой компании. Решается также через антикапча-сервисы: нужно передать параметр sitekey (берется из кода страницы, обычно в элементе с классом h-captcha или iframe src) и pageurl. Отличие - часто требуется прокси, потому что hCaptcha проверяет соответствие IP токена и запроса. 2Captcha предлагает режим proxyless для hCaptcha, но он работает не на всех сайтах - иногда без прокси решение не принимается, и тогда надо указывать proxy, как и с reCAPTCHA.

В коде с twocaptcha это может выглядеть так:
result = solver.hcaptcha(sitekey="SITEKEY_HCAPTCHA", url="https://target.site/page")
token = result['code']
Далее токен подставляется в поле h-captcha-response и отправляется. Если используете Selenium, возможно, нужно вызвать JS-функцию завершения проверки (аналогично reCAPTCHA).
FunCaptcha (Arkose Labs): капча, где обычно требуется выполнить интерактивную задачу (например, повернуть картинку правильно). Без автоматизации такие капчи очень сложны - не получить токен без реального взаимодействия. К счастью, сервисы вроде 2Captcha умеют их решать. Вы предоставляете так называемый public_key (аналог sitekey) и некоторый svc_url (адрес бэкенда Arkose). Например, для Arkose может потребоваться передать параметр blob - зашифрованные данные с сайта. 2Captcha в своей библиотеке имеет метод solver.funcaptcha(...) для этого. SolveCaptcha также заявляет поддержку Arkose.
Ограничения: FunCaptcha обязательно проверяет IP-адрес. Поэтому при решении через сервис нужны прокси (лучше минимум резидентные). В 2Captcha вы можете указать proxy в методе funcaptcha. Решение возвращает токен (обычно это парные значения, например token и session - см. документацию Arkose).
Распознавание капчи с выбором изображений, координат и слайдеры (GeeTest и др.)
Некоторые капчи требуют указать объект на изображении или перетащить ползунок. Решение таких задач программно возможно двумя путями:
Использовать API антикапча-сервиса, который вернёт либо координаты для клика, либо специальный токен разблокировки.
Попытаться решить самостоятельно с помощью компьютерного зрения.
Пример - капча типа "Click CAPTCHA", где показывается изображение и нужно кликнуть по определённому объекту. 2Captcha умеет это решать: нужно отправить изображение и указать количество кликов. В ответ придут координаты.
GeeTest и слайдеры: капча GeeTest обычно состоит из изображения-пазла и ползунка, которым нужно этот пазл поставить в правильное положение. Решение через сервисы бывает двух видов:

Через токен: Некоторые сервисы могут вернуть готовое решение GeeTest в виде набора ключей (validate, challenge и др.), которые нужно отправить сайту.
Через эмуляцию действий: В ряде случаев (как с Buster для аудио-капчи) open-source решения пытаются сами двигать слайдер, но это не всегда надежно.
2Captcha и SolveCaptcha заявляют поддержку GeeTest. Для интеграции обычно нужно передать ряд параметров, которые есть на странице (например, gt и challenge - идентификаторы с сайта). Получив ответ, его нужно подставить в соответствующие поля (часто через JS или hidden inputs) и выполнить продолжение проверки.
Прочие сложные капчи: Существуют и другие специфические капчи (например, Яндекс капчи, VK капчи с выбором изображений из набора, сложные математические и пр.). Большинство из них тоже по силам перечисленным сервисам.
Полезные библиотеки для распознавания капчи
В экосистеме Python есть ряд модулей, облегчающих работу с различными сервисами антикапчи и даже позволяющих менять провайдеров на лету:
2captcha-python - официальный модуль для API 2Captcha. Поддерживает все типы капч, прокси, асинхронный режим, регулярно обновляется. Идеален, если вы выбрали сервис 2Captcha и цените официальную поддержку.
solvecaptcha-python - аналогичный модуль от SolveCaptcha. Позволяет решать reCAPTCHA, hCaptcha, FunCaptcha, Turnstile, GeeTest и др. через API SolveCaptcha. Синтаксис близок к 2Captcha, а API совместим со схемой 2Captcha, так что перейти не сложно.
captcha_solver (Python RuCaptcha) - еще одна библиотека для RuCaptcha/2Captcha.
2captcha-solver - сторонний модуль, заточенный под решение reCAPTCHA (v2/v3), hCaptcha, FunCaptcha. Он менее универсален, чем официальный, но поддерживает асинхронность и может быть полезен для массовых параллельных решений.
captchatools - интересная библиотека, поддерживающая несколько сервисов (2Captcha, AntiCaptcha, etc.) сразу. Позволяет указать основной сервис и резервные: если первый не решил капчу (или баланс кончился), автоматически перекинет на запасной. Также поддерживает прокси и async. Это удобно для повышения надежности скриптов.
twocaptcha-extension-python - вспомогательный модуль для интеграции 2Captcha с Selenium/Playwright. Если ваш парсер сильно завязан на браузерную автоматизацию, этот модуль упрощает решение капчи прямо в браузере без установки расширений - достаточно иметь API-ключ. Но он бесполезен вне контекста Selenium.
Кроме того, есть клиенты практически под все языки программирования (Node.js, PHP, C# и т.д.), а также браузерные расширения. В частности, 2Captcha и SolveCaptcha предлагают плагин для браузера: вы вводите API-ключ, и расширение само на страницах находит и решает капчи, подставляя ответы.
Заключение
Таким образом, нужно следовать правилу - предупрежден, значит вооружен. Для защиты нужно:
Маскировать активность с помощью прокси и user-agent ротации (чтобы не возникало лишних подозрений).
Писать парсер, имитирующий человеческие паттерны (паузы, последовательность действий) насколько возможно.
Быть готовым к появлению CAPTCHA и автоматизировать её решение через сторонние сервисы, используя доступные Python-интеграции.

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