Integrations

Smartproxy + CaptchaAI: настройка резидентных прокси для решения CAPTCHA

Связка работает по простому правилу: трафик страницы идёт через резидентный шлюз Smartproxy, а задача CAPTCHA уходит в API CaptchaAI напрямую. Прокси отвечает за то, с какого IP сайт видит ваш запрос, CaptchaAI — за токен, который вы кладёте в форму. Большая часть проблем в такой интеграции возникает именно тогда, когда эти две роли путают.

Ниже — рабочая схема: какой пул брать, как удержать один IP на весь цикл «загрузка — решение — отправка», как это выглядит в Python, Selenium и Node.js и что делать с типовыми сбоями.


Какой шлюз Smartproxy выбрать под задачу

Пулы Smartproxy по-разному ведут себя на страницах с проверками. Ориентир по документации провайдера:

Тип Размер пула Под какие задачи Как часто всплывает CAPTCHA
Резидентный 55 млн+ IP Общий парсинг Низко
Датацентровый 100 тыс.+ IP Быстрая выкачка данных Средне-высоко
Мобильный 10 млн+ IP Мобильные версии сайтов Очень низко
ISP (статический резидентный) Статические IP резидентного уровня Долгие сессии Низко

Вывод один: если проверки появляются на каждом запросе, вы почти наверняка сидите на датацентровом шлюзе. Резидентный или ISP-пул снижает их частоту, но не убирает — решатель в пайплайне нужен в любом случае.


Шаг 1: базовая связка на Python

Учётные данные шлюза и API-ключ держите в переменных окружения — в примере они вынесены в константы только для читаемости. Задача уходит в in.php, результат забирается опросом res.php.

import requests
import time

SMARTPROXY_USER = "spuser"
SMARTPROXY_PASS = "sppassword"
SMARTPROXY_HOST = "gate.smartproxy.com"
SMARTPROXY_PORT = 10001

CAPTCHAAI_KEY = "YOUR_API_KEY"
CAPTCHAAI_URL = "https://ocr.captchaai.com"

proxies = {
    "http": f"http://{SMARTPROXY_USER}:{SMARTPROXY_PASS}@{SMARTPROXY_HOST}:{SMARTPROXY_PORT}",
    "https": f"http://{SMARTPROXY_USER}:{SMARTPROXY_PASS}@{SMARTPROXY_HOST}:{SMARTPROXY_PORT}",
}


def fetch_page(url):
    return requests.get(url, proxies=proxies, timeout=30)


def solve_captcha(site_url, sitekey, captcha_type="recaptcha_v2"):
    submit_data = {
        "key": CAPTCHAAI_KEY,
        "pageurl": site_url,
        "json": 1,
    }

    if captcha_type == "turnstile":
        submit_data["method"] = "turnstile"
        submit_data["sitekey"] = sitekey
    else:
        submit_data["method"] = "userrecaptcha"
        submit_data["googlekey"] = sitekey

    resp = requests.post(f"{CAPTCHAAI_URL}/in.php", data=submit_data)
    data = resp.json()
    if data["status"] != 1:
        raise Exception(f"Submit failed: {data['request']}")

    task_id = data["request"]

    for _ in range(60):
        time.sleep(5)
        resp = requests.get(f"{CAPTCHAAI_URL}/res.php", params={
            "key": CAPTCHAAI_KEY,
            "action": "get",
            "id": task_id,
            "json": 1,
        })
        data = resp.json()
        if data["request"] == "CAPCHA_NOT_READY":
            continue
        if data["status"] == 1:
            return data["request"]
        raise Exception(f"Solve: {data['request']}")

    raise TimeoutError("Timeout")

Обратите внимание: запрос к CaptchaAI идёт без прокси. Решателю нужны только pageurl и sitekey; прокси остаётся на слое fetch_page. Если разнести эти два слоя сразу, дальнейшая отладка становится вдвое короче.


Шаг 2: sticky-сессии — почему без них токен отклоняют

Это главная причина, по которой «всё работает, но форма не проходит». Ротируемый шлюз меняет IP между запросами: страницу вы загрузили с одного адреса, а форму отправили уже с другого. Сайт видит несовпадение и отбрасывает токен, хотя решение было корректным. Лечится закреплением IP на весь цикл — в имя пользователя добавляется идентификатор сессии и её длительность.

import random
import string


def get_sticky_proxy(session_duration_minutes=10):
    """Create a sticky session proxy (same IP for duration)."""
    session_id = "".join(random.choices(string.ascii_lowercase + string.digits, k=8))

    proxy_url = (
        f"http://{SMARTPROXY_USER}"
        f"-session-{session_id}"
        f"-sessionduration-{session_duration_minutes}"
        f":{SMARTPROXY_PASS}@{SMARTPROXY_HOST}:{SMARTPROXY_PORT}"
    )

    return {"http": proxy_url, "https": proxy_url}


# Use same IP for entire CAPTCHA workflow
sticky = get_sticky_proxy(session_duration_minutes=10)

# Page load
resp = requests.get("https://staging.example.com/qa-form", proxies=sticky)

# Solve CAPTCHA
token = solve_captcha("https://staging.example.com/qa-form", "SITEKEY_HERE")

# Submit with same IP
resp = requests.post(
    "https://target.com/submit",
    data={"g-recaptcha-response": token},
    proxies=sticky,
)

Десяти минут хватает на типовой сценарий: открыли страницу, дождались решения, отправили форму. Для многошаговых форм — регистрация в несколько экранов, длинные заявки, анкеты — ставьте 30 минут.


Шаг 3: выбор страны выхода

Гео-таргетинг тоже задаётся через имя пользователя, отдельный endpoint для этого не нужен.

# Smartproxy country targeting via username
def get_country_proxy(country_code):
    proxy_url = (
        f"http://{SMARTPROXY_USER}"
        f"-country-{country_code}"
        f":{SMARTPROXY_PASS}@{SMARTPROXY_HOST}:{SMARTPROXY_PORT}"
    )
    return {"http": proxy_url, "https": proxy_url}

# US proxy
us_proxy = get_country_proxy("us")

# UK proxy
uk_proxy = get_country_proxy("gb")

# Germany proxy
de_proxy = get_country_proxy("de")

Типичный локальный случай: команда в Алматы или Минске тестирует форму регистрации европейского сервиса. Из локального датацентрового адреса страница встретит вас проверкой, а иногда и языковой версией не того рынка. Резидентный выход в нужной стране плюс sticky-сессия дают воспроизводимый прогон QA, а не «как повезло с IP».

И оговорка про данные: собирайте только то, что вы вправе обрабатывать — 152-ФЗ «О персональных данных» для российских пользователей, привычная GDPR-дисциплина для трансграничных проектов.


Шаг 4: Selenium с прокси и подстановкой токена

Схема та же, но авторизация через --proxy-server в Chrome не передаётся: логин и пароль придётся отдавать через Selenium Wire или расширение. Идентификатор сессии обязателен и здесь.

from selenium import webdriver
from selenium.webdriver.common.by import By


def create_smartproxy_driver(country=None, sticky_session=None):
    proxy_user = SMARTPROXY_USER
    if country:
        proxy_user += f"-country-{country}"
    if sticky_session:
        proxy_user += f"-session-{sticky_session}"

    proxy_url = f"{proxy_user}:{SMARTPROXY_PASS}@{SMARTPROXY_HOST}:{SMARTPROXY_PORT}"

    options = webdriver.ChromeOptions()
    options.add_argument(f"--proxy-server=http://{SMARTPROXY_HOST}:{SMARTPROXY_PORT}")
    options.add_argument("--disable-blink-features=AutomationControlled")
    options.add_argument("--window-size=1920,1080")

    # For authenticated proxies, use seleniumwire or extension
    return webdriver.Chrome(options=options)


def scrape_with_captcha(url, country="us"):
    session_id = "".join(random.choices(string.ascii_lowercase, k=8))
    driver = create_smartproxy_driver(country=country, sticky_session=session_id)

    try:
        driver.get(url)
        time.sleep(3)

        sitekey = driver.execute_script(
            "return document.querySelector('[data-sitekey]')?.getAttribute('data-sitekey')"
        )

        if sitekey:
            token = solve_captcha(url, sitekey)
            driver.execute_script(f"""
                document.querySelector('#g-recaptcha-response').value = '{token}';
            """)
            driver.find_element(By.CSS_SELECTOR, "form").submit()
            time.sleep(3)

        return driver.page_source

    finally:
        driver.quit()

Подстановка токена в #g-recaptcha-response — стандартный приём для reCAPTCHA v2. У Cloudflare Turnstile поле ответа называется иначе, поэтому при переключении типа проверки не забудьте поменять и селектор, и метод отправки задачи.


Шаг 5: то же самое на Node.js

Логика не меняется: агент прокси навешивается на запрос к целевой странице, вызов CaptchaAI идёт напрямую.

const axios = require("axios");
const HttpsProxyAgent = require("https-proxy-agent");

const CAPTCHAAI_KEY = "YOUR_API_KEY";

function getSmartproxyAgent(options = {}) {
  let user = "spuser";
  if (options.country) user += `-country-${options.country}`;
  if (options.session) user += `-session-${options.session}`;

  return new HttpsProxyAgent(
    `http://${user}:[email protected]:10001`
  );
}

async function scrapeWithCaptcha(url, sitekey) {
  const agent = getSmartproxyAgent({
    country: "us",
    session: `sess-${Date.now()}`,
  });

  // Fetch page through proxy
  const pageResp = await axios.get(url, { httpsAgent: agent });

  // Solve CAPTCHA via CaptchaAI (no proxy needed)
  const submitResp = await axios.post(
    "https://ocr.captchaai.com/in.php",
    null,
    {
      params: {
        key: CAPTCHAAI_KEY,
        method: "userrecaptcha",
        googlekey: sitekey,
        pageurl: url,
        json: 1,
      },
    }
  );

  const taskId = submitResp.data.request;

  // Poll for result
  for (let i = 0; i < 60; i++) {
    await new Promise((r) => setTimeout(r, 5000));

    const result = await axios.get("https://ocr.captchaai.com/res.php", {
      params: {
        key: CAPTCHAAI_KEY,
        action: "get",
        id: taskId,
        json: 1,
      },
    });

    if (result.data.request === "CAPCHA_NOT_READY") continue;
    if (result.data.status === 1) return result.data.request;
  }

  throw new Error("Timeout");
}

Шаг 6: параллельная обработка и потоки

На очереди из сотен страниц вы упираетесь в два лимита: параллельные соединения шлюза Smartproxy и число потоков в тарифе CaptchaAI. Тарификация идёт по количеству одновременных задач, а не решений, и в пределах месяца решения по потоку не ограничены.

Ориентир простой: max_workers не должен превышать число потоков тарифа, иначе часть задач встанет в очередь. BASIC ($15/мес, 5 потоков) закрывает отладку, STANDARD ($30/мес, 15 потоков) — регулярный QA-пайплайн, ADVANCE ($90/мес, 50 потоков) — параллельный парсинг. Выше идут PREMIUM ($170/мес, 100 потоков), CORPORATE ($240/мес, 150 потоков), ENTERPRISE ($300/мес, 200 потоков) и линейка VIP-1 ($1,500/мес, 1000 потоков), VIP-2 ($4,500/мес, 3000 потоков), VIP-3 ($7,500/мес, 5000 потоков). Цены в USD.

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

from concurrent.futures import ThreadPoolExecutor, as_completed


def process_url(url):
    session_id = "".join(random.choices(string.ascii_lowercase, k=8))
    proxy = get_sticky_proxy(10)

    try:
        resp = requests.get(url, proxies=proxy, timeout=30)

        # Check if CAPTCHA is present (simplified detection)
        if "data-sitekey" in resp.text:
            import re
            match = re.search(r'data-sitekey="([^"]+)"', resp.text)
            if match:
                sitekey = match.group(1)
                token = solve_captcha(url, sitekey)
                return {"url": url, "status": "solved", "token": token[:30]}

        return {"url": url, "status": "no_captcha"}

    except Exception as e:
        return {"url": url, "status": "error", "error": str(e)}


urls = [
    "https://site1.com/page",
    "https://site2.com/page",
    "https://site3.com/page",
]

with ThreadPoolExecutor(max_workers=5) as executor:
    futures = {executor.submit(process_url, u): u for u in urls}

    for future in as_completed(futures):
        result = future.result()
        print(f"[{result['status']}] {result['url']}")

Разбор типовых сбоев

Симптом Причина Что сделать
407 Proxy Authentication Required Неверный формат логина или пароля шлюза Сверьте учётные данные в панели управления Smartproxy; проверьте, не потерялись ли суффиксы -country- и -session-
IP меняется посреди сценария Sticky-сессия не задана Добавьте -session-ID и -sessionduration- в имя пользователя
Проверка появляется на каждом запросе Работа идёт через датацентровый шлюз Переключитесь на резидентный или ISP-пул
Долгие ответы Перегруженная гео-цель Возьмите другую страну или город выхода
Токен отклонён после успешного решения IP сменился между загрузкой страницы и отправкой формы Увеличьте длительность sticky-сессии
CAPCHA_NOT_READY не сменяется результатом Неверная конфигурация задачи или слишком ранний опрос Проверьте sitekey и pageurl; интервал опроса 5 с уже заложен в примере

Отладку начинайте с разделения слоёв: сначала убедитесь, что страница открывается через прокси (fetch_page без решателя), и только потом подключайте CaptchaAI.


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

Нужно ли отправлять запросы к CaptchaAI через Smartproxy?

Нет. Вызовы in.php и res.php идут напрямую с вашего сервера: прокси нужен целевому сайту, а не решателю, и лишний хоп только добавит задержку.

Можно ли передать IP Smartproxy в саму задачу CaptchaAI?

Да — в запросе на отправку поддерживается параметр proxy. Это имеет смысл, когда сайт жёстко привязывает выданную проверку к адресу, с которого её запросили.

Какие типы CAPTCHA закрывает эта схема?

reCAPTCHA v2 (включая invisible и Enterprise), reCAPTCHA v3, Cloudflare Turnstile и Challenge, GeeTest v3, изображения, текстовые и grid-задачи, BLS CAPTCHA. CaptchaFox (beta), Friendly Captcha (beta) и Lemin (beta) — в бете. hCaptcha и FunCaptcha не поддерживаются, GeeTest v4 заявлен как скорый, но пока недоступен. Меняется только параметр method в запросе — прокси-обвязка остаётся той же.

Сколько потоков брать под очередь из 1000 страниц?

Считайте от параллелизма, а не от объёма: если вы обрабатываете 15 страниц одновременно и проверка встречается примерно на трети, 15 потоков дают запас. Решения в пределах потока отдельно не тарифицируются, так что более высокий тариф берут ради скорости.

Правда ли, что мобильный пул реже упирается в проверки?

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


Связанные материалы


Соберите пайплайн один раз: резидентный выход Smartproxy, sticky-сессия и решатель. Получите API-ключ CaptchaAI и начните с первой формы в staging.

Комментарии для этой статьи отключены.