API Tutorials

SOCKS5 Proxy + CaptchaAI: Руководство по установке и настройке

SOCKS5-прокси встраивается не «внутрь» решения CAPTCHA, а рядом с ним: трафик к целевому сайту идёт через туннель, а запросы к in.php и res.php уходят напрямую. Если разобрать это разделение один раз, отпадает добрая половина вопросов вида «почему прокси работает, а токен не принимается». Ниже — рабочие конфигурации SOCKS5 для requests, aiohttp, Selenium, Node.js и Puppeteer, передача прокси в саму задачу через proxytype, а также разбор ошибок, которые в этой связке встречаются чаще всего.


Чем SOCKS5 отличается от HTTP-прокси

SOCKS5 работает на транспортном уровне и просто пробрасывает TCP- (а при поддержке — и UDP-) соединение, ничего не дописывая в запрос. HTTP-прокси разбирает запрос целиком и может добавлять служебные заголовки. Отсюда все практические различия:

Характеристика HTTP/HTTPS-прокси SOCKS5-прокси
Поддержка протоколов Только HTTP/HTTPS Любой TCP, при поддержке — UDP
Работа с заголовками Может добавить X-Forwarded-For Запрос не изменяется
Скорость Быстрее на коротких запросах Немного медленнее из-за рукопожатия
Аутентификация Basic/Digest Имя пользователя и пароль
Разрешение DNS На стороне клиента На стороне прокси (socks5h)
WebSocket Ограниченно Полностью

Для сценариев с CAPTCHA важнее всего две последние строки: современные виджеты активно используют WebSocket, а socks5h избавляет от расхождения между IP запроса и IP DNS-резолвера.


Два канала трафика: сайт через прокси, API — напрямую

Прежде чем писать код, зафиксируйте маршруты. В типовом пайплайне их ровно два:

  • Через SOCKS5 идёт всё, что относится к целевому сайту: загрузка страницы, чтение sitekey, отправка формы, WebSocket-соединения виджета.
  • Напрямую идут вызовы CaptchaAI. API не требует прокси, а заворачивание его в тот же туннель только добавляет лишний круг задержки к каждому из десятков опросов res.php.
  • Исключение — когда проверку нужно решать с того же выходного IP, что и запрос к сайту. Тогда прокси передаётся в саму задачу параметрами proxy и proxytype (раздел ниже), а не подставляется в HTTP-клиент.

Разделение полезно и при отладке: если страница не открывается — виноват прокси, если задача висит в CAPCHA_NOT_READY — дело в параметрах запроса к API, и прокси тут ни при чём.


Настройка в Python

requests + PySocks: базовая связка

Поддержка SOCKS в requests ставится отдельным экстра-пакетом:

pip install requests[socks] pysocks

Дальше — полный цикл: страница читается через туннель, sitekey вынимается регулярным выражением, решение запрашивается напрямую, а форма отправляется обратно через тот же прокси. Обратите внимание на схему socks5h — именно она отдаёт разрешение имён прокси-серверу:

import requests
import time

SOCKS5_HOST = "proxy.example.com"
SOCKS5_PORT = 1080
SOCKS5_USER = "proxyuser"
SOCKS5_PASS = "proxypass"

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

# SOCKS5 proxy configuration
proxies = {
    "http": f"socks5h://{SOCKS5_USER}:{SOCKS5_PASS}@{SOCKS5_HOST}:{SOCKS5_PORT}",
    "https": f"socks5h://{SOCKS5_USER}:{SOCKS5_PASS}@{SOCKS5_HOST}:{SOCKS5_PORT}",
}
# socks5h = DNS resolved by proxy server (recommended)
# socks5  = DNS resolved locally


def fetch_through_socks(url):
    """Fetch URL through SOCKS5 proxy."""
    return requests.get(
        url,
        proxies=proxies,
        headers={
            "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
            "AppleWebKit/537.36 Chrome/126.0.0.0 Safari/537.36"
        },
        timeout=30,
    )


def solve_captcha(site_url, sitekey):
    """Solve CAPTCHA via CaptchaAI (direct, no proxy needed)."""
    resp = requests.post(f"{CAPTCHAAI_URL}/in.php", data={
        "key": CAPTCHAAI_KEY,
        "method": "userrecaptcha",
        "googlekey": sitekey,
        "pageurl": site_url,
        "json": 1,
    })
    data = resp.json()
    if data["status"] != 1:
        raise Exception(f"Submit: {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")


# Full workflow
resp = fetch_through_socks("https://staging.example.com/qa-form")

import re
match = re.search(r'data-sitekey="([^"]+)"', resp.text)
if match:
    token = solve_captcha("https://staging.example.com/qa-form", match.group(1))
    # Submit with token through same proxy
    resp = requests.post(
        "https://target.com/submit",
        data={"g-recaptcha-response": token},
        proxies=proxies,
    )

Тайм-аут в 30 с на сетевом запросе и 60 итераций опроса с шагом 5 с — разумные стартовые значения. На мобильных и нестабильных каналах тайм-аут лучше поднять, а не увеличивать число повторов.

aiohttp: асинхронный вариант

Если воркер обслуживает несколько задач одновременно, синхронный requests быстро упрётся в ожидание. Пакет aiohttp_socks подключает SOCKS5 как обычный коннектор:

import aiohttp
import aiohttp_socks
import asyncio


async def fetch_async(url):
    connector = aiohttp_socks.ProxyConnector.from_url(
        f"socks5://{SOCKS5_USER}:{SOCKS5_PASS}@{SOCKS5_HOST}:{SOCKS5_PORT}"
    )

    async with aiohttp.ClientSession(connector=connector) as session:
        async with session.get(url) as resp:
            return await resp.text()


asyncio.run(fetch_async("https://staging.example.com/qa-form"))

Selenium: SOCKS5 с аутентификацией и без

Chrome принимает SOCKS5 через флаг --proxy-server, но логин и пароль в командной строке не передаются — это ограничение самого браузера, а не драйвера. Поэтому вариантов два: прокси без аутентификации (или с привязкой по IP) через штатные опции, либо selenium-wire, который поднимает локальный перехватчик и уже сам держит учётные данные:

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


def create_socks5_driver(host, port, username=None, password=None):
    options = webdriver.ChromeOptions()

    # SOCKS5 proxy (no auth via command line)
    options.add_argument(f"--proxy-server=socks5://{host}:{port}")

    # DNS through proxy
    options.add_argument("--host-resolver-rules=MAP * ~NOTFOUND, EXCLUDE 127.0.0.1")

    options.add_argument("--disable-blink-features=AutomationControlled")
    options.add_argument("--window-size=1920,1080")

    driver = webdriver.Chrome(options=options)
    return driver


# For authenticated SOCKS5, use seleniumwire
from seleniumwire import webdriver as sw_webdriver

def create_auth_socks5_driver():
    options = {
        "proxy": {
            "http": f"socks5h://{SOCKS5_USER}:{SOCKS5_PASS}@{SOCKS5_HOST}:{SOCKS5_PORT}",
            "https": f"socks5h://{SOCKS5_USER}:{SOCKS5_PASS}@{SOCKS5_HOST}:{SOCKS5_PORT}",
        }
    }

    chrome_options = sw_webdriver.ChromeOptions()
    chrome_options.add_argument("--disable-blink-features=AutomationControlled")

    return sw_webdriver.Chrome(
        seleniumwire_options=options,
        options=chrome_options,
    )


# Usage
driver = create_auth_socks5_driver()
driver.get("https://staging.example.com/qa-form")
time.sleep(3)

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

if sitekey:
    token = solve_captcha("https://staging.example.com/qa-form", sitekey)
    driver.execute_script(f"""
        document.querySelector('#g-recaptcha-response').value = '{token}';
    """)
    driver.find_element(By.CSS_SELECTOR, "form").submit()

driver.quit()

Правило --host-resolver-rules здесь нужно, чтобы браузер не резолвил домены мимо туннеля. Для прокси с привязкой по IP это самый короткий путь: добавьте адрес своего сервера в белый список у провайдера и работайте без пароля вовсе.


Node.js: SocksProxyAgent и axios

В Node.js SOCKS5 подключается агентом, который назначается и на httpAgent, и на httpsAgent. Вызовы CaptchaAI в этом примере намеренно оставлены без агента:

const { SocksProxyAgent } = require("socks-proxy-agent");
const axios = require("axios");

const CAPTCHAAI_KEY = "YOUR_API_KEY";

const socksAgent = new SocksProxyAgent(
  "socks5h://proxyuser:[email protected]:1080"
);

async function fetchViaSocks(url) {
  return axios.get(url, {
    httpsAgent: socksAgent,
    httpAgent: socksAgent,
    headers: {
      "User-Agent":
        "Mozilla/5.0 (Windows NT 10.0; Win64; x64) Chrome/126.0.0.0",
    },
  });
}

async function solveCaptcha(siteUrl, sitekey) {
  // CaptchaAI calls don't go through SOCKS proxy
  const submit = await axios.post(
    "https://ocr.captchaai.com/in.php",
    null,
    {
      params: {
        key: CAPTCHAAI_KEY,
        method: "userrecaptcha",
        googlekey: sitekey,
        pageurl: siteUrl,
        json: 1,
      },
    }
  );

  const taskId = submit.data.request;

  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");
}

Puppeteer: запуск браузера через SOCKS5

Puppeteer наследует ту же логику, что и Chrome в Selenium: адрес прокси задаётся аргументом запуска, а учётные данные — методом page.authenticate() уже на уровне страницы:

const puppeteer = require("puppeteer");

async function launchWithSocks5() {
  const browser = await puppeteer.launch({
    args: [
      "--proxy-server=socks5://proxy.example.com:1080",
      "--no-sandbox",
      "--window-size=1920,1080",
    ],
  });

  const page = await browser.newPage();

  // Authenticate if needed
  await page.authenticate({
    username: "proxyuser",
    password: "proxypass",
  });

  await page.goto("https://staging.example.com/qa-form", { waitUntil: "networkidle0" });

  const sitekey = await page.evaluate(() =>
    document.querySelector("[data-sitekey]")?.getAttribute("data-sitekey")
  );

  if (sitekey) {
    const token = await solveCaptcha(page.url(), sitekey);
    await page.evaluate((t) => {
      document.querySelector("#g-recaptcha-response").value = t;
    }, token);
  }

  await browser.close();
}

Ожидание networkidle0 на страницах с виджетом иногда не наступает: фоновые запросы CAPTCHA держат соединение. Если сборка подвисает, замените условие на domcontentloaded и дождитесь появления элемента [data-sitekey] явно.


Передача SOCKS5-прокси в задачу CaptchaAI

Когда сайт сверяет IP, с которого получен токен, прокси нужно передать в запрос на решение. Формат параметра — type:host:port:user:pass, тип дублируется в proxytype:

def solve_with_proxy(site_url, sitekey, proxy_url):
    """Pass proxy to CaptchaAI for IP-matched solving."""
    # Format: type:host:port:user:pass
    proxy_param = f"socks5:{SOCKS5_HOST}:{SOCKS5_PORT}:{SOCKS5_USER}:{SOCKS5_PASS}"

    resp = requests.post(f"{CAPTCHAAI_URL}/in.php", data={
        "key": CAPTCHAAI_KEY,
        "method": "userrecaptcha",
        "googlekey": sitekey,
        "pageurl": site_url,
        "proxy": proxy_param,
        "proxytype": "SOCKS5",
        "json": 1,
    })

    data = resp.json()
    if data["status"] != 1:
        raise Exception(f"Submit: {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":
            return data["request"]

    raise TimeoutError("Timeout")

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


Диагностика типичных сбоев

Симптом Вероятная причина Что сделать
Connection refused Неверный хост или порт Проверьте, что сервер SOCKS5 запущен и порт открыт
Запросы видят реальный DNS Схема socks5:// вместо socks5h:// Переключитесь на socks5h:// — DNS уйдёт на прокси
Ошибка аутентификации Неверные учётные данные Проверьте пару логин/пароль командой curl --socks5
Высокие задержки Выход прокси далеко от целевого сайта Возьмите точку выхода ближе к целевому домену
WebSocket не поднимается Сервер SOCKS5 без поддержки UDP Смените сервер на вариант с UDP
Токен получен, форма отклонена Страница и решение шли с разных IP Передайте прокси в задачу через proxytype

Сколько потоков нужно и сколько это стоит

Счёт в CaptchaAI выставляется за потоки, а не за количество решённых задач: поток — это один слот параллельного выполнения, который освобождается сразу после возврата токена. На старте хватает плана BASIC ($15/мес, 5 потоков); если параллельных воркеров с SOCKS5-сессиями становится больше десятка, логичный следующий шаг — STANDARD ($30/мес, 15 потоков).

Практический ориентир: считайте не число прокси, а число одновременно открытых форм. Три воркера, каждый из которых держит свою SOCKS5-сессию и решает одну проверку за раз, укладываются в 5 потоков с запасом на повторы. Точку выхода выбирайте по географии целевого сайта, а не своего сервера: выход во Франкфурте для европейского домена даст меньший RTT, чем выход в Центральной Азии, даже если скрипт запущен там.

Если через прокси собираются не только технические ответы, помните про 152-ФЗ «О персональных данных» и сопоставимые нормы в других юрисдикциях: собирайте только то, что вы вправе обрабатывать. Фиксированная цена в USD за поток удобна тем, что бюджет известен заранее и не зависит от объёма трафика через туннель.


Частые вопросы

Почему запрос уходит мимо прокси, хотя proxies заданы?

Чаще всего мешают переменные окружения HTTP_PROXY/ALL_PROXY либо сессия, созданная до подстановки словаря. Проверьте фактический выход запросом к сервису, возвращающему IP, и убедитесь, что схема — socks5h, а не socks5.

Как проверить SOCKS5-прокси до запуска скрипта?

Одной командой: curl --socks5-hostname user:pass@host:1080 https://example.com. Если curl проходит, а Python — нет, дело в коде или в переменных окружения, а не в прокси.

Обязательно ли решать проверку с того же IP, что и запрос к странице?

Не всегда, но для reCAPTCHA v2 и Cloudflare Turnstile на строгих настройках совпадение IP заметно повышает долю принятых токенов. Начните без прокси в задаче и подключите proxytype, если форма отклоняет валидные токены.

Почему Chrome игнорирует логин и пароль прокси?

Браузер не принимает учётные данные в --proxy-server. Используйте прокси с привязкой по IP или selenium-wire для Selenium и page.authenticate() для Puppeteer.


Смежные руководства


Настройте SOCKS5 один раз и подключите решение CAPTCHA к своему пайплайну — получите API-ключ.

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