Все статьиРуководства8 мин

Веб-скрейпер на Python: создание инструмента с обходом антибот-защит

Как построить надёжный Python-скрейпер, обходящий Cloudflare и антибот-системы: от httpx и Pydantic до stealth-режима, CAPTCHA и масштабирования до 10 000 страниц.

Команда InfraProxy

21 февраля 2026 г.

#Python#антибот#Cloudflare#httpx#асинхронный скрейпинг

Почему связка requests + BeautifulSoup больше не работает в 2026 году

Классический стек — requests для HTTP и BeautifulSoup для парсинга HTML — десятилетиями использовался для сбора данных. Сегодня он перестаёт быть достаточным для большинства коммерчески значимых источников.

Проблема 1: TLS-отпечаток. Python-библиотека requests использует стандартную реализацию SSL/TLS из OpenSSL. Её JA3/JA4-отпечаток отличается от отпечатка реального Chrome. Антибот-системы (Cloudflare, DataDome, PerimeterX) проверяют отпечаток; несоответствие User-Agent и TLS ведёт к блокировке.

Проблема 2: JavaScript. Большая часть современного контента рендерится в браузере. Запрос через requests возвращает пустой или неполный HTML — данные подгружаются через XHR/Fetch после выполнения скриптов.

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

Проблема 4: CAPTCHA. При малейшем подозрении пользователю показывается CAPTCHA. requests не может ни пройти JavaScript-челлендж, ни решить визуальную задачу.

Для легального сбора данных с защищённых сайтов нужен другой подход: либо полноценный headless-браузер, либо специализированный API для скрейпинга, который решает эти задачи за вас.

Архитектура: Scraper API как слой обхода антиботов

Scraper API — это облачный сервис, который принимает URL и возвращает готовый HTML (или структурированные данные). Внутри он использует:

  • Резидентные прокси с ротацией
  • Реальные браузерные TLS-отпечатки
  • JavaScript-рендеринг (Playwright/Puppeteer)
  • Автоматическое решение CAPTCHA
  • Повторные попытки при блокировках

Вы пишете простой клиент на Python: отправляете запросы к API, получаете данные, парсите их локально. Вся логика обхода защит инкапсулирована в сервисе.

Преимущества такого подхода:

  • Быстрый старт без настройки инфраструктуры
  • Предсказуемая стоимость (плата за успешный запрос)
  • Актуальные обновления обхода при изменении защит
  • Возможность сосредоточиться на бизнес-логике (извлечение, хранение, аналитика)

Настройка Python-окружения

Для работы с Scraper API достаточно стандартных библиотек HTTP и валидации данных:

# requirements.txt
httpx>=0.27.0
pydantic>=2.0.0

httpx — современная асинхронная HTTP-библиотека с поддержкой HTTP/2, совместимая с requests по интерфейсу. pydantic — для описания схем извлекаемых данных и валидации ответов.

import httpx
from pydantic import BaseModel

class ScraperClient:
    def __init__(self, api_key: str, base_url: str = "https://api.example.com/v1"):
        self.api_key = api_key
        self.base_url = base_url

    async def scrape(self, url: str, render_js: bool = True) -> str:
        async with httpx.AsyncClient(timeout=60.0) as client:
            resp = await client.post(
                f"{self.base_url}/scrape",
                json={"url": url, "render_js": render_js},
                headers={"Authorization": f"Bearer {self.api_key}"}
            )
            resp.raise_for_status()
            return resp.json()["html"]

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

Обход Cloudflare в stealth-режиме

Cloudflare блокирует запросы по нескольким признакам: IP из дата-центров, несовпадение TLS и User-Agent, отсутствие выполнения JavaScript-челленджей. Scraper API по умолчанию использует stealth-настройки:

  • Резидентные прокси — IP домашних провайдеров с высокой репутацией
  • Полноценный браузерный стек — TLS-отпечаток Chrome, корректные заголовки
  • Выполнение челленджей — headless Chrome проходит проверки так же, как обычный браузер
  • Задержки и ротация — запросы распределяются по разным IP с паузами между ними

При необходимости можно явно указать параметры:

  • country — геотаргетинг (например, для локальных вариантов сайта)
  • proxy_type: "residential" — принудительное использование резидентных прокси
  • bypass_level: "advanced" — для сайтов с усиленной защитой

Для большинства задач достаточно стандартных настроек; тонкая подстройка нужна только при низком success rate.

Обработка CAPTCHA

Даже при качественных прокси CAPTCHA иногда появляется — reCAPTCHA v3, hCaptcha, Cloudflare Turnstile. Scraper API обычно интегрирован с сервисами решения CAPTCHA:

  • Автоматическое определение появления CAPTCHA на странице
  • Отправка задачи в сервис решения (ИИ или ручной)
  • Подстановка токена и повторная отправка запроса

С вашей стороны ничего делать не нужно — API обрабатывает CAPTCHA прозрачно. Стоимость решения, как правило, включается в стоимость запроса (или тарифицируется отдельно по факту). Важно отслеживать долю запросов, требующих CAPTCHA: если она растёт, возможны проблемы с прокси или частотой запросов.

LLM-экстракция структурированных данных

Классический парсинг опирается на CSS/XPath-селекторы. При частых изменениях вёрстки селекторы ломаются, парсеры требуют доработки. Альтернатива — извлечение с помощью LLM: вы передаёте HTML (или текст) и схему полей, модель возвращает структурированный JSON.

class Product(BaseModel):
    title: str
    price: float
    currency: str
    in_stock: bool

# В запросе к API указываем extract_schema на основе Pydantic-модели
extract_schema = {
    "title": {"type": "string"},
    "price": {"type": "number"},
    "currency": {"type": "string"},
    "in_stock": {"type": "boolean"}
}

API, поддерживающий AI-экстракцию, принимает такую схему и возвращает готовый JSON. Преимущества: устойчивость к редизайнам, работа с неструктурированным текстом. Недостатки: выше стоимость и время ответа. Для стабильных источников CSS-селекторы остаются экономичным вариантом; LLM имеет смысл для разнородных или часто меняющихся сайтов.

Масштабирование до 10 000 страниц: асинхронный батчинг

При объёмах в тысячи страниц критична параллельность. Синхронные запросы в цикле работают слишком медленно. Необходим асинхронный подход с ограничением concurrency, чтобы не превышать лимиты API и не перегружать целевые сайты.

import asyncio
from httpx import AsyncClient, Limits

async def scrape_batch(urls: list[str], api_key: str, max_concurrent: int = 10) -> list[dict]:
    limits = Limits(max_connections=20, max_keepalive_connections=10)
    results = []

    async def fetch_one(client: AsyncClient, url: str) -> dict | None:
        try:
            resp = await client.post(
                "https://api.example.com/v1/scrape",
                json={"url": url, "render_js": True},
                headers={"Authorization": f"Bearer {api_key}"}
            )
            resp.raise_for_status()
            return {"url": url, "html": resp.json()["html"], "status": "ok"}
        except Exception as e:
            return {"url": url, "error": str(e), "status": "failed"}

    async with AsyncClient(timeout=60.0, limits=limits) as client:
        sem = asyncio.Semaphore(max_concurrent)
        async def limited_fetch(url):
            async with sem:
                return await fetch_one(client, url)
        tasks = [limited_fetch(url) for url in urls]
        results = await asyncio.gather(*tasks)

    return results

Ключевые моменты:

  • Semaphore — ограничение одновременных запросов (например, 10–20)
  • Connection pooling — переиспользование соединений через AsyncClient
  • Обработка ошибок — логирование неудачных URL для повторной обработки
  • Ретраи — экспоненциальный backoff при 429/503

При 10 000 URL и 10 параллельных запросах, при среднем времени ответа 5 секунд, полный прогон займёт ориентировочно 1–2 часа (с учётом ограничений и повторов).

Компромиссы и практические выводы

Плюсы Scraper API:

  • Не нужно поддерживать инфраструктуру обхода (прокси, браузеры, CAPTCHA)
  • Быстрый вывод продукта на рынок
  • Предсказуемая стоимость при переменных объёмах

Минусы:

  • Зависимость от провайдера
  • При очень больших стабильных объёмах собственное решение с прокси может быть дешевле
  • Ограничения по кастомизации (особые заголовки, сложные сценарии взаимодействия)

Гибридный подход:

  • Простые, незащищённые сайты — собственный скрейпер + прокси InfraProxy
  • Защищённые маркетплейсы, площадки с вакансиями, соцсети — Scraper API
  • Комбинирование обоих вариантов в одном пайплайне

Для старта разумно начать с API: проверить гипотезу, оценить success rate и стоимость. При росте объёмов и стабилизации требований можно перенести часть нагрузки на DIY-решение с качественными резидентными прокси.

InfraProxy предоставляет резидентные прокси для DIY-скрейпинга и совместим с популярными Scraper API. Надёжные IP, ротация, поддержка HTTP/HTTPS/SOCKS5. Рассчитайте стоимость.

Нужны надёжные прокси для вашего проекта?

InfraProxy предоставляет серверные и резидентные прокси для российского бизнеса. Договор, постоплата, техподдержка.