Обработка CAPTCHA при скрапинге

Типы CAPTCHA, стратегии предотвращения, которые эффективнее решения, и ключевая роль прокси в избежании CAPTCHA. Код для обнаружения и маршрутизации.

Обработка CAPTCHA при скрапинге

Почему CAPTCHA — главное препятствие для скрапера

CAPTCHA существуют для разделения людей и ботов, и они становятся всё эффективнее. Когда скрапер сталкивается с CAPTCHA, это значит, что целевой сайт обнаружил автоматизированное поведение — частота запросов была слишком высокой, IP имеет низкий уровень доверия или отпечаток браузера выглядел подозрительно. Лучшая стратегия CAPTCHA — предотвращение, а не решение.

Это руководство охватывает типы CAPTCHA, с которыми вы столкнётесь, почему предотвращение эффективнее и дешевле решения, и как прокси играют ключевую роль в полном избежании CAPTCHA.

Эта статья — часть нашей серии Полное руководство по прокси для веб-скрапинга. О системах обнаружения — Как антибот-системы обнаруживают прокси.

Типы CAPTCHA в 2026 году

ТипКак работаетСложность обхода
reCAPTCHA v2 (чекбокс)Клик «Я не робот» + возможная визуальная задачаСредняя
reCAPTCHA v3 (невидимая)Оценивает поведение 0.0-1.0 без взаимодействияВысокая
hCaptchaЗадачи выбора изображений (аналог reCAPTCHA v2)Средняя
Cloudflare TurnstileБраузерная проверка, обычно невидимаяВысокая
Кастомные CAPTCHAСпецифичные задачи сайта (искажённый текст, пазлы)Варьируется
Proof of WorkБраузер должен вычислить хэш (Cloudflare Under Attack)Средняя

Невидимые CAPTCHA — настоящая угроза

Самые опасные CAPTCHA для скраперов — те, которые вы не видите. reCAPTCHA v3 и Cloudflare Turnstile работают в фоне, анализируя движения мыши, поведение прокрутки, паттерны набора и окружение браузера. Они назначают оценку доверия без показа челленджа — и если оценка слишком низкая, запрос тихо блокируется или перенаправляется.

Предотвращение vs решение: почему предотвращение побеждает

ПодходСтоимость за CAPTCHAСкоростьНадёжностьМасштабируемость
Предотвращение (CAPTCHA не появляются)$0МгновенноНаивысшаяОтличная
Сервисы решения CAPTCHA$1-3 за 100010-60 секунд85-95%Умеренная
ИИ-автосолвинг$2-5 за 10005-30 секунд70-90%Ограниченная
В масштабе предотвращение экономит и деньги, и время. Решение 100 000 CAPTCHA в день стоит $100-500 и добавляет часы задержки. Предотвращение не стоит ничего сверх правильного управления прокси и запросами.

Стратегия предотвращения 1: Используйте качественные резидентные прокси

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

import requests
# Residential proxy — high trust score, fewer CAPTCHAs
PROXY = "http://USERNAME:PASSWORD@gate.proxyhat.com:8080"
def scrape_with_residential(url: str) -> str:
    """Use residential proxies to avoid triggering CAPTCHAs."""
    session = requests.Session()
    session.proxies = {"http": PROXY, "https": PROXY}
    session.headers.update({
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
                      "AppleWebKit/537.36 (KHTML, like Gecko) "
                      "Chrome/120.0.0.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",
    })
    resp = session.get(url, timeout=30)
    return resp.text

Резидентный пул ProxyHat предоставляет IP от реальных провайдеров в 190+ странах, обеспечивая каждому запросу максимально высокий уровень доверия. Смотрите Резидентные vs датацентр-прокси для скрапинга для детального сравнения.

Стратегия предотвращения 2: Реалистичные паттерны запросов

CAPTCHA часто срабатывают от роботизированных паттернов поведения, а не только от репутации IP. Сделайте скрапер похожим на человека:

Реализация на Python

import requests
import random
import time
PROXY = "http://USERNAME:PASSWORD@gate.proxyhat.com:8080"
USER_AGENTS = [
    "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 Chrome/120.0.0.0 Safari/537.36",
    "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 Chrome/120.0.0.0 Safari/537.36",
    "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:121.0) Gecko/20100101 Firefox/121.0",
    "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 Safari/605.1.15",
]
REFERRERS = [
    "https://www.google.com/",
    "https://www.bing.com/",
    "https://duckduckgo.com/",
    None,  # Direct visit
]
def human_like_scrape(urls: list[str]) -> list[str]:
    """Scrape with realistic human behavior patterns."""
    results = []
    session = requests.Session()
    session.proxies = {"http": PROXY, "https": PROXY}
    for url in urls:
        # Randomize headers per request
        headers = {
            "User-Agent": random.choice(USER_AGENTS),
            "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",
            "Connection": "keep-alive",
            "Upgrade-Insecure-Requests": "1",
        }
        referrer = random.choice(REFERRERS)
        if referrer:
            headers["Referer"] = referrer
        try:
            resp = session.get(url, headers=headers, timeout=30)
            results.append(resp.text)
        except requests.RequestException:
            results.append(None)
        # Human-like delays: 1-5 seconds with occasional longer pauses
        if random.random() < 0.1:
            time.sleep(random.uniform(5, 15))  # 10% chance of long pause
        else:
            time.sleep(random.uniform(1, 4))
    return results

Реализация на Node.js

const HttpsProxyAgent = require('https-proxy-agent');
const fetch = require('node-fetch');
const agent = new HttpsProxyAgent('http://USERNAME:PASSWORD@gate.proxyhat.com:8080');
const USER_AGENTS = [
  'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 Chrome/120.0.0.0 Safari/537.36',
  'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 Chrome/120.0.0.0 Safari/537.36',
  'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:121.0) Gecko/20100101 Firefox/121.0',
];
function randomDelay() {
  const isLongPause = Math.random() < 0.1;
  const ms = isLongPause
    ? 5000 + Math.random() * 10000
    : 1000 + Math.random() * 3000;
  return new Promise(r => setTimeout(r, ms));
}
async function humanLikeScrape(urls) {
  const results = [];
  for (const url of urls) {
    const headers = {
      'User-Agent': USER_AGENTS[Math.floor(Math.random() * USER_AGENTS.length)],
      'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
      'Accept-Language': 'en-US,en;q=0.9',
    };
    try {
      const res = await fetch(url, { agent, headers, timeout: 30000 });
      results.push(await res.text());
    } catch {
      results.push(null);
    }
    await randomDelay();
  }
  return results;
}

Стратегия предотвращения 3: Умная ротация IP

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

import requests
import uuid
def create_session_for_site(site_id: str):
    """Create a sticky session that maintains the same IP per site.
    This avoids the suspicious pattern of different IPs accessing the same flow."""
    session_id = uuid.uuid5(uuid.NAMESPACE_URL, site_id).hex[:8]
    proxy = f"http://USERNAME-session-{session_id}:PASSWORD@gate.proxyhat.com:8080"
    session = requests.Session()
    session.proxies = {"http": proxy, "https": proxy}
    return session
# Same IP for all requests to a specific product section
session = create_session_for_site("example.com-electronics")
page1 = session.get("https://example.com/electronics?page=1")
page2 = session.get("https://example.com/electronics?page=2")
page3 = session.get("https://example.com/electronics?page=3")
# Different IP for a different section
session2 = create_session_for_site("example.com-clothing")
clothes1 = session2.get("https://example.com/clothing?page=1")

Подробнее о паттернах ротации — Стратегии ротации прокси для масштабного скрапинга.

Стратегия предотвращения 4: Соблюдайте лимиты скорости

CAPTCHA часто являются эскалацией после ограничения скорости. Если правильно обрабатывать сигналы лимитов, CAPTCHA встречаются редко:

import requests
import time
PROXY = "http://USERNAME:PASSWORD@gate.proxyhat.com:8080"
CAPTCHA_INDICATORS = [
    "captcha",
    "recaptcha",
    "hcaptcha",
    "challenge",
    "verify you are human",
    "please complete the security check",
]
def is_captcha_page(html: str) -> bool:
    """Detect if the response is a CAPTCHA challenge page."""
    html_lower = html.lower()
    return any(indicator in html_lower for indicator in CAPTCHA_INDICATORS)
def scrape_with_captcha_detection(urls: list[str]) -> list[dict]:
    results = []
    session = requests.Session()
    session.proxies = {"http": PROXY, "https": PROXY}
    captcha_count = 0
    backoff = 2.0
    for url in urls:
        try:
            resp = session.get(url, timeout=30)
            if resp.status_code == 200 and not is_captcha_page(resp.text):
                results.append({"url": url, "status": "success", "body": resp.text})
                captcha_count = 0
                backoff = max(backoff * 0.9, 1.0)  # Reduce backoff on success
            elif is_captcha_page(resp.text) or resp.status_code == 403:
                captcha_count += 1
                results.append({"url": url, "status": "captcha"})
                if captcha_count >= 3:
                    # Too many CAPTCHAs — increase backoff significantly
                    backoff = min(backoff * 3, 60)
                    print(f"CAPTCHA streak: {captcha_count}. Backing off to {backoff:.0f}s")
                else:
                    backoff = min(backoff * 1.5, 30)
        except requests.RequestException as e:
            results.append({"url": url, "status": "error", "error": str(e)})
        time.sleep(backoff)
    return results

Подробнее о стратегиях лимитов скорости — Лимиты скорости при скрапинге.

Когда CAPTCHA неизбежна: обнаружение и маршрутизация

Даже при идеальном предотвращении некоторые CAPTCHA неизбежны. Встройте обнаружение в конвейер для маршрутизации CAPTCHA-страниц на специальную обработку:

import requests
from enum import Enum
PROXY = "http://USERNAME:PASSWORD@gate.proxyhat.com:8080"
class ResponseType(Enum):
    SUCCESS = "success"
    CAPTCHA = "captcha"
    BLOCKED = "blocked"
    ERROR = "error"
def classify_response(resp: requests.Response) -> ResponseType:
    """Classify a response to determine next action."""
    if resp.status_code == 403:
        return ResponseType.BLOCKED
    if resp.status_code == 429:
        return ResponseType.BLOCKED
    if resp.status_code == 200:
        html = resp.text.lower()
        captcha_signals = ["captcha", "recaptcha", "hcaptcha", "cf-challenge"]
        if any(s in html for s in captcha_signals):
            return ResponseType.CAPTCHA
        return ResponseType.SUCCESS
    return ResponseType.ERROR
def scrape_with_routing(urls: list[str]) -> dict:
    """Scrape URLs and route based on response classification."""
    session = requests.Session()
    session.proxies = {"http": PROXY, "https": PROXY}
    results = {"success": [], "captcha": [], "blocked": [], "error": []}
    for url in urls:
        try:
            resp = session.get(url, timeout=30)
            response_type = classify_response(resp)
            results[response_type.value].append(url)
            if response_type == ResponseType.CAPTCHA:
                # Route to CAPTCHA queue for manual or service-based solving
                print(f"CAPTCHA detected: {url}")
            elif response_type == ResponseType.BLOCKED:
                # Rotate IP and retry
                print(f"Blocked: {url}")
        except requests.RequestException:
            results["error"].append(url)
    print(f"Success: {len(results['success'])}, "
          f"CAPTCHAs: {len(results['captcha'])}, "
          f"Blocked: {len(results['blocked'])}")
    return results

Чек-лист предотвращения CAPTCHA

  • Используйте резидентные прокси. У них наивысший уровень доверия и минимальная частота CAPTCHA. Резидентные прокси ProxyHat предоставляют миллионы чистых IP.
  • Устанавливайте реалистичные заголовки. Всегда отправляйте User-Agent, Accept, Accept-Language и другие стандартные браузерные заголовки.
  • Добавляйте человекоподобные задержки. Случайные 1-5 секундные задержки с периодическими длинными паузами.
  • Правильно поддерживайте сессии. Используйте cookies и постоянные IP для связанных запросов через липкие сессии.
  • Уважайте robots.txt. Сайты, обнаружившие нарушение robots.txt, быстрее эскалируют до CAPTCHA.
  • Мониторьте частоту CAPTCHA. Если процент CAPTCHA превышает 5%, нужно исправлять подход.
  • Избегайте скрапинга в пиковые часы. Антибот-системы агрессивнее в периоды высокого трафика.
  • Правильно ротируйте User-Agent. Используйте свежие, реалистичные строки браузеров. Не смешивайте мобильные и десктопные UA в одной сессии.

Настройка прокси на вашем языке: Использование прокси в Python, Использование прокси в Node.js или Использование прокси в Go. Изучите ProxyHat для веб-скрапинга.

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

Помогают ли прокси избежать CAPTCHA?

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

Какой самый дешёвый способ обработки CAPTCHA в масштабе?

Предотвращение. Инвестиции в резидентные прокси и правильные паттерны скрапинга стоят гораздо меньше, чем сервисы решения в масштабе. Решение стоит $1-3 за 1000, но добавляет 10-60 секунд задержки на запрос.

Помогают ли headless-браузеры с CAPTCHA?

Они помогают с невидимыми CAPTCHA (reCAPTCHA v3, Turnstile), предоставляя реальное браузерное окружение с исполнением JavaScript. Однако они медленнее и ресурсоёмче. Используйте только для целей, специально требующих браузерной верификации.

Как узнать, что я получаю CAPTCHA-страницы?

Проверяйте HTML ответов на индикаторы CAPTCHA: «captcha», «recaptcha», «hcaptcha», «challenge» или «verify you are human». Также отслеживайте неожиданные 403 ответы и редиректы на URL челленджей. Встройте автоматическое обнаружение в конвейер скрапинга.

Почему я всё ещё получаю CAPTCHA с резидентными прокси?

Обычно из-за паттернов запросов, а не качества IP. Частые причины: слишком много запросов в минуту, отсутствие браузерных заголовков, проблемы с обработкой cookies или слишком систематичные паттерны. Замедлитесь, добавьте дрожание и используйте липкие сессии для связанных запросов.

Готовы начать?

Доступ к более чем 50 млн резидентных IP в 148+ странах с AI-фильтрацией.

Смотреть ценыРезидентные прокси
← Вернуться в Блог