Парсер блокируется, потому что не выглядит как трафик, которого ожидает цель. Реальные браузеры несут согласованный набор сигналов: правдоподобный IP, полный набор заголовков, TLS-отпечаток, соответствующий заявленному User-Agent, и ритм запросов, который не похож на метроном. Уберите любой из них, и современная антибот-система это заметит. Большая часть работы по парсингу без блокировок состоит в том, чтобы вернуть эти сигналы в правильном порядке, и платить за тяжёлые только тогда, когда цель действительно этого требует.

Этот материал проходит техники примерно в том порядке, в котором они окупаются: ротируйте свой IP, отправляйте правдоподобный запрос, сглаживайте свою частоту, уважайте то, что объявляет сайт, отрисовывайте JavaScript, когда страница в этом нуждается, и передавайте всё целиком управляемой точке, когда нескольких заголовков уже недостаточно. Ни одна из них не серебряная пуля. Сложенные в правильном порядке, они доводят вас от стены 403 до устойчивого 200 на большинстве целей в большинстве случаев.

Самые быстрые победы, по порядку

Техника Какую блокировку останавливает Усилия
Ротируйте свой IP Ограничения частоты на один IP, жёсткие баны по IP Низкие
Отправляйте реалистичные заголовки + User-Agent Наивное распознавание ботов по отпечатку Низкие
Регулируйте темп и сбавляйте Распознавание по скорости, ответы 429 Низкие
Согласуйте TLS с вашим User-Agent Проверки несовпадения отпечатков Средние
Отрисовывайте JavaScript Пустой HTML, проверки на JavaScript Средние
Передайте управляемому API Весь стек сразу Наименьшие, платно

Начните сверху, измерьте свою долю блокировок и поднимайтесь, только когда цель вас вынуждает. Тянуться за парком headless-браузеров, чтобы спарсить статичную страницу с ценой, это потраченные впустую усилия; тянуться за простым requests против укреплённой стены входа это потраченные впустую запросы.

Ротируйте свой IP

Самая частая блокировка самая простая: слишком много запросов с одного адреса. Сайт считает запросы на один IP и начинает возвращать ответы 429 или страницу блокировки, как только вы пересекаете его порог. Распределите эти запросы по множеству IP, и ни один адрес никогда не сработает ограничение. В этом и вся причина того, что инфраструктура парсинга это в основном прокси-инфраструктура: прокси делает запрос за вас, поэтому цель видит его IP, а не ваш.

IP, через который вы ротируете, имеет такое же значение, как и сама ротация. IP центров обработки данных быстры и дёшевы, но находятся в известных хостинговых диапазонах, поэтому цель, которая выполняет поиск по ASN, помечает их мгновенно. Резидентные IP выходят с реальных потребительских подключений и читаются как обычные посетители, при более высокой стоимости и более низкой скорости. Полный компромисс описан в материале прокси центров обработки данных против резидентных, а промежуточный вариант статических резидентных в материале ISP против резидентных прокси. Покупайте ровно столько доверия, сколько требует цель, и ни на уровень больше.

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

python
# Rotate exits through a single gateway endpoint.
# The gateway picks a fresh IP; your logic stays here.
import requests

proxies = {
    "http": "http://_USER_TOKEN_:@smartproxy.crawlbase.com:8012",
    "https": "http://_USER_TOKEN_:@smartproxy.crawlbase.com:8012",
}
resp = requests.get("https://example.com/product/123", proxies=proxies, verify=False)
print(resp.status_code)

Отправляйте запрос, который отправил бы настоящий браузер

HTTP-клиент по умолчанию выдаёт себя в первой же строке. Библиотека Python requests отправляет User-Agent: python-requests/2.x и почти никаких других заголовков; настоящий браузер отправляет дюжину, в определённом порядке. Сайты, которые делают не больше, чем читают эти заголовки, заблокируют первый и пропустят второй.

Установите актуальный, настоящий User-Agent браузера и ротируйте через небольшой пул из них, а не молотите одной строкой. Затем отправляйте заголовки, которые всегда путешествуют вместе с ним: Accept, Accept-Language, Accept-Encoding и правдоподобный Referer. Цель не в одном волшебном заголовке, а во внутренней согласованности: User-Agent Chrome в паре с заголовками Accept в стиле Firefox более подозрителен, чем вообще никакой подмены.

python
import requests

headers = {
    "User-Agent": (
        "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) "
        "AppleWebKit/537.36 (KHTML, like Gecko) "
        "Chrome/124.0 Safari/537.36"
    ),
    "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
    "Accept-Language": "en-US,en;q=0.9",
    "Accept-Encoding": "gzip, deflate, br",
    "Referer": "https://www.google.com/",
}
resp = requests.get("https://example.com", headers=headers)

Согласуйте свой TLS-отпечаток с вашим User-Agent

Заголовки это очевидный слой; TLS это тот, который ловит парсеров, починивших заголовки и остановившихся на этом. Прежде чем будет отправлен хоть один байт HTTP, ваш клиент открывает TLS-рукопожатие, и точная форма этого рукопожатия (порядок шифров, расширения, поддерживаемые группы) образует отпечаток, который обычно суммируется в виде хеша JA3. Настоящий Chrome производит один хорошо известный отпечаток. Python requests производит совершенно другой. Когда вы отправляете User-Agent Chrome поверх TLS-стека Python, эти двое не сходятся, и проверка отпечатка помечает несовпадение, насколько бы безупречны ни были ваши заголовки.

Решение в том, чтобы заставить само рукопожатие выглядеть как браузер. Используйте клиент, который имитирует TLS-профиль настоящего браузера (в Python curl_cffi с его опцией impersonate это распространённый выбор), или управляйте настоящим движком браузера, который производит подлинное рукопожатие бесплатно. Именно здесь самодельный парсинг начинает становиться дорогим, и где управляемая точка, которая уже обрабатывает отпечатки, начинает выглядеть привлекательно.

Согласованность важнее скрытности

Антибот-системы редко блокируют по одному плохому сигналу; они блокируют по сигналам, которые противоречат друг другу. IP центра обработки данных с безупречным набором заголовков браузера, User-Agent Chrome с TLS-отпечатком Python, десктопный UA с мобильным Accept-Language: каждое противоречие это флаг. Стремитесь к запросу, где IP, заголовки, TLS и поведение рассказывают одну и ту же историю.

Регулируйте темп и сбавляйте

Даже по множеству IP парсер, который выпускает запросы быстрее, чем мог бы кликать любой человек, читается как автоматизированный. Добавьте рандомизированную задержку между запросами, а не фиксированную (фиксированный промежуток в 500 мс сам по себе отпечаток), и держите параллелизм на уровне, который цель может поглотить, не замечая.

Важнее установившейся задержки то, как вы реагируете на отпор. Когда сервер возвращает 429 или 503, он говорит вам сбавить темп. Уважьте это: отступайте экспоненциально, уважайте заголовок Retry-After, когда он присутствует, и относитесь к всплеску ответов 429 как к сигналу снизить общую частоту, а не повторять упорнее. Повтор запроса к ограниченной по частоте точке на полной скорости это то, как мягкий троттлинг становится жёстким баном.

python
import time, random, requests

def fetch(url, headers, tries=4):
    for attempt in range(tries):
        resp = requests.get(url, headers=headers)
        if resp.status_code == 200:
            return resp
        if resp.status_code in (429, 503):
            wait = int(resp.headers.get("Retry-After", 2 ** attempt))
            time.sleep(wait + random.uniform(0, 1))
            continue
        resp.raise_for_status()
    raise RuntimeError("exhausted retries")

Если вы застряли, расшифровывая, какой код состояния что означает, материал коды ошибок статуса прокси проходит по распространённым из них и тому, что каждый на самом деле вам сообщает.

Уважайте robots.txt и оставайтесь на публичных данных

Перед техниками обхода дисциплина, которая удерживает вас от неприятностей: прочитайте robots.txt сайта, уважайте его crawl-delay и запрещённые пути и парсите публичные страницы, а не что-либо за входом в систему. Это отчасти вежливость, отчасти самосохранение. Аутентифицированный парсинг привязывает каждый запрос к учётной записи, которую сайт может забанить в один клик, а игнорирование объявленных правил это и самый быстрый способ получить пометку, и черта, где начинаются юридические вопросы.

Связанная ловушка это ханипот: ссылка, скрытая от человеческих глаз с помощью CSS (display:none, нулевой размер, позиционирование за экраном), но присутствующая в HTML. Наивный обходчик, который следует за каждым <a>, идёт прямо в неё и выдаёт себя как бота. Следуйте только за ссылками, которые отрисованный браузер действительно показал бы, и пропускайте всё визуально скрытое.

Отрисовывайте JavaScript, когда страница в этом нуждается

Множество страниц возвращают почти пустой HTML и строят своё реальное содержимое с помощью JavaScript после загрузки. Получите одну из таких простым HTTP-клиентом, и вы получите оболочку без данных. Хуже того, некоторые сайты выдают проверку на JavaScript: небольшой скрипт, который должен выполниться и пройти, прежде чем будет доставлена реальная страница, и который небраузерный клиент никогда не сможет пройти.

В обоих случаях вам нужен настоящий движок браузера. Headless-браузер (Playwright, Puppeteer или Selenium, управляющий Chrome) загружает страницу, выполняет её скрипты и отдаёт вам DOM, который увидел бы пользователь. Он также производит подлинный TLS-отпечаток браузера и реальный объект navigator, поэтому проходит класс проверок, который сырой клиент пройти не может. Цена в весе: headless-браузер использует гораздо больше CPU и памяти на страницу, чем HTTP-запрос, поэтому приберегите его для страниц, которые действительно нуждаются в отрисовке. Более подробный разбор смотрите в материале веб-парсинг на Python и Selenium.

Одна оговорка: headless-браузер по умолчанию обнаружим. Флаг navigator.webdriver, отсутствующие или странные списки плагинов и специфичные для headless особенности все утекают. Стелс-плагины замазывают распространённые признаки, но это гонка вооружений, и на укреплённой цели это часто момент, чтобы перестать поддерживать собственный парк.

Когда передать управляемому API

Каждая техника выше это слой, который вы строите и поддерживаете: пул прокси, ротатор заголовков, клиент, имитирующий TLS, политика отступа, headless-парк со стелс-патчами. На терпимых целях вам могут понадобиться только первые две. На укреплённой вы в итоге собираете и нянчите все из них, и CAPTCHA или новая проверка на JavaScript может сломать весь конвейер за одну ночь.

Crawling API сворачивает этот стек в один запрос. Вы отправляете URL; провайдер выбирает происхождение IP, отправляет согласованный отпечаток, отрисовывает страницу, когда требуется браузер, повторяет при блокировках на стороне сервера и возвращает готовый HTML. Компромисс честен: вы платите за запрос и отдаёте часть низкоуровневого контроля в обмен на то, чтобы не запускать антибот-инфраструктуру как вторую работу.

Crawlbase Crawling API

Когда цели нужно больше, чем чистый IP, Crawling API владеет всем стеком: он ротирует по пулу из более чем 140 млн IP с выходами центров обработки данных, резидентными и мобильными, отправляет правдоподобный отпечаток, отрисовывает JavaScript, когда страница этого требует, и повторяет при блокировках на стороне сервера. Вы отправляете URL и получаете результат. Сначала прогоните через него свою реальную цель на бесплатном тарифе.

python
# Send the URL; rotation, fingerprint, rendering,
# and retries are handled server-side.
import requests

resp = requests.get(
    "https://api.crawlbase.com/",
    params={
        "token": "_YOUR_TOKEN_",
        "url": "https://example.com/product/123",
        "javascript": "true",  # render the page in a browser
    },
)
print(resp.text)

Строите вы или покупаете, вопрос прокси внизу никуда не девается. Если вы всё ещё выбираете слой IP, материал лучшие прокси для веб-парсеров сопоставляет типы целей с типом прокси, который подходит, а материал как использовать ротируемые прокси охватывает встраивание ротации в ваш код.

Итоги

Ключевые выводы

  • Блокировки приходят из несогласованности. Заставьте свой IP, заголовки, TLS и тайминг рассказывать одну и ту же историю; одного противоречия достаточно, чтобы получить пометку.
  • Сначала ротируйте IP. Большинство блокировок это ограничения частоты на один IP, и распределение запросов по пулу это самое дешёвое исправление с наибольшим эффектом.
  • Чините заголовки и TLS вместе. User-Agent браузера поверх TLS-стека Python более подозрителен, чем вообще никакой подмены.
  • Уважайте сайт. Уважайте robots.txt, сбавляйте при ответах 429, избегайте ханипотов и оставайтесь на публичных данных.
  • Отрисовывайте только когда нужно и разгружайте, когда становится тяжело. Приберегите headless-браузеры для страниц, насыщенных JavaScript, и тянитесь за управляемым API, как только цель даёт отпор на каждом слое.

Часто задаваемые вопросы

Какова самая частая причина блокировки парсера?

Слишком много запросов с одного IP-адреса. Сайты считают запросы на один IP и начинают возвращать ответы 429 или страницы блокировки, как только вы пересекаете порог. Ротация запросов по пулу IP, так что ни один адрес не срабатывает ограничение, это единственное исправление с наибольшим эффектом, поэтому ротация IP обычно первая техника для применения.

Достаточно ли смены User-Agent, чтобы избежать блокировок?

На наименее защищённых сайтах иногда. На чём-либо серьёзном нет. Реалистичный User-Agent должен быть в паре с полным набором заголовков, которые отправляет браузер, TLS-отпечатком, соответствующим этому браузеру, и правдоподобной частотой запросов. Подменённый User-Agent поверх TLS-стека HTTP-клиента по умолчанию это противоречие, которое проверки отпечатков легко ловят.

Всегда ли мне нужен headless-браузер для парсинга?

Нет. Headless-браузер нужен только тогда, когда страница строит своё содержимое с помощью JavaScript после загрузки или выдаёт проверку на JavaScript, которую небраузерный клиент пройти не может. Для статичного HTML простой HTTP-запрос гораздо быстрее и дешевле. Приберегите headless-браузер для страниц, которые действительно требуют отрисовки, поскольку он стоит гораздо больше CPU и памяти на страницу.

Как мне обработать ответ 429 Too Many Requests?

Сбавьте темп, а не повторяйте упорнее. Отступайте экспоненциально, уважайте заголовок Retry-After, когда сервер его присылает, и относитесь к серии ответов 429 как к сигналу снизить общую частоту запросов. Молотить ограниченную по частоте точку на полной скорости это то, как временный троттлинг превращается в жёсткий бан.

Стоит ли мне парсить данные за входом в систему?

Избегайте этого, где можете. Аутентифицированные запросы привязывают каждый вызов к учётной записи, которую сайт может забанить мгновенно, и они поднимают юридические вопросы и вопросы условий обслуживания, которых парсинг публичных страниц не поднимает. Прочитайте robots.txt сайта, оставайтесь на публичных данных и пропускайте ссылки-ханипоты, скрытые от реальных пользователей.

Когда управляемый API для парсинга имеет больше смысла, чем построение собственного?

Когда цель даёт отпор на нескольких слоях сразу. Поддержание пула прокси, ротации заголовков, клиента, имитирующего TLS, логики отступа и headless-парка со стелс-патчами это реальная инженерная нагрузка, и новая CAPTCHA или проверка может сломать его за одну ночь. Crawling API поглощает всё это за одним запросом, так что вы меняете стоимость за запрос и часть контроля на то, чтобы не запускать антибот-инфраструктуру самостоятельно.

Начать создавать

Обходите любой сайт в масштабе, без борьбы с инфраструктурой.

Crawlbase берёт на себя прокси, отпечатки и CAPTCHA, чтобы ваша команда выпускала конвейеры данных вместо поддержки обвязки краулинга. 1 000 запросов бесплатно, без карты.

Самообслуживание · Звонок отдела продаж не требуется · Доступны корпоративные объёмы краулинга