Как избежать капчи при парсинге (без нарушения правил)
Большинство капч при парсинге — это реакция на трафик, который выглядит автоматизированным. Самый дешёвый способ с ними справиться — перестать их провоцировать. Для этого нужно сначала искать легитимный источник данных, узнать, что разрешают правила сайта, отправлять меньше и медленнее запросы и не загружать одну и ту же страницу дважды. Решение капчи — запасной вариант для случаев, которых нельзя избежать, а не основной план.
Сначала проверьте официальный API или фид
Многие сайты, которые парсят, уже предлагают способ получить те же данные без капчи: публичный API, экспорт данных, RSS- или sitemap-фид либо партнёрскую программу. Официальный источник надёжнее, реже меняется без предупреждения и даёт владельцу сайта право голоса в том, как вы его используете. Ищите:
- раздел для разработчиков или API в футере сайта,
sitemap.xmlсо списком страниц,- RSS- или Atom-ссылки в
<head>страницы, - страницу «data» или «download» для массовых выгрузок.
Если один из этих вариантов покрывает вашу задачу, используйте его. Большинства капч удастся избежать, если вообще не запрашивать HTML.
Уважайте robots.txt и заданную в нём паузу
robots.txt говорит, какие пути автоматические клиенты могут запрашивать и иногда сколько ждать между запросами. Стандартная библиотека Python может прочитать его за вас:
import time
from urllib.robotparser import RobotFileParser
import requests
USER_AGENT = "ExampleBot/1.0 (+https://example.com/bot)"
parser = RobotFileParser()
parser.set_url("https://example.com/robots.txt")
parser.read()
delay = parser.crawl_delay(USER_AGENT) or 5 # если не задано, берём осторожные 5 секунд
urls = [
"https://example.com/products?page=1",
"https://example.com/products?page=2",
]
last_request = 0.0
for url in urls:
if not parser.can_fetch(USER_AGENT, url):
print("skipped by robots.txt:", url)
continue
wait = delay - (time.monotonic() - last_request)
if wait > 0:
time.sleep(wait)
resp = requests.get(url, headers={"User-Agent": USER_AGENT}, timeout=30)
last_request = time.monotonic()
print(url, resp.status_code)
Если robots.txt запрещает путь, честный ответ — не трогать его или спросить владельца. Обход этого запрета через браузер ничего не меняет в том, о чём просил сайт.
Замедляйтесь и распределяйте запросы
Ровный умеренный темп редко вызывает проверку, а всплеск почти всегда её вызывает. Несколько привычек дают большую разницу:
- Выберите один темп запросов для сайта и держитесь его, а не работайте на полной скорости.
- Добавьте случайный разброс (jitter), чтобы ритм не был идеально ровным.
- Делайте паузу, когда видите 429 или страницу с капчей.
- Запускайте задачи в непиковые часы, если нагрузка на сайт — проблема.
Кешируйте и не загружайте повторно
Каждый запрос, который вы не сделали, — это запрос, который сайту не нужно обработать. Сохраняйте загруженные страницы вместе с датой и хешем тела и запрашивайте их снова только тогда, когда содержимое, вероятно, изменилось. Условные запросы с заголовками If-Modified-Since или ETag позволяют серверу дешёво ответить «не изменилось», если он это поддерживает.
Переиспользуйте сессии и отправляйте обычные заголовки
Сессия, которая сохраняет cookie между запросами, ведёт себя больше как посетитель, чем скрипт, который каждый раз стартует с нуля. Используйте requests.Session() для каждого сайта и отправляйте понятный, честный User-Agent с названием вашего бота и контактом. Не выдавайте себя за браузер, чтобы обойти правило. Если сайту нужен JavaScript для показа контента, используйте инструмент на базе браузера для этих страниц и соблюдайте те же лимиты частоты.
Когда капча всё же появляется
Некоторые сайты покажут капчу, как бы аккуратно вы ни работали. Определите её в коде и остановите задачу, а не долбите страницу. Обнаружение и опциональное решение для PopularCaptcha описаны в гайде капча при парсинге.
Спланируйте обход до старта
Обход, который каждый день загружает всё подряд, — самый простой способ вызвать капчу. Сначала спланируйте работу:
- Расставьте приоритеты. Решите, какие страницы меняются часто, а какие редко. Часто меняющиеся обходите чаще, остальные — реже.
- Используйте даты из sitemap. Во многих sitemap есть значение
lastmod. Пропускайте URL, которые не менялись с вашего последнего визита. - Обходите инкрементально. Сохраняйте время последней успешной загрузки каждого URL и продолжайте с него, а не начинайте с первой страницы после сбоя.
- Распределяйте нагрузку. Разбивайте большой список на пачки и запускайте их в течение дня, а не всё сразу.
Такой план снижает число запросов, а это самый большой рычаг, который у вас есть.
Запишите план в виде короткого конфиг-файла или таблицы: сайты, разделы, интервал обновления и дневной бюджет запросов для каждого. Когда бюджет исчерпан, задача ждёт следующего окна. Относиться к бюджету как к жёсткому лимиту, а не как к рекомендации — это то, что не даёт краулеру уйти в паттерн трафика, который и вызывает капчу. Пересматривайте бюджет каждые несколько недель: сайт растёт, и его трафик тоже может вырасти, а то, что было деликатным в прошлом квартале, сейчас может таким не быть.
Парсите ответственно
- Перед стартом проверьте
robots.txtи условия использования и следуйте им. - Держите низкую частоту запросов и останавливайтесь, когда сайт показывает, что ему тяжело.
- Не собирайте персональные данные, которые вам не нужны, и удаляйте их, когда они перестают быть нужны.
- Не публикуйте защищённый авторским правом контент массово. Используйте данные для анализа, сравнения или собственного продукта и указывайте источник там, где это уместно.
- Если нужен большой объём, свяжитесь с владельцем сайта. Возможно, он предложит фид.