API Tutorials

Proxy SOCKS5 + CaptchaAI: Guia de instalação e configuração

Três decisões resolvem quase todo problema de SOCKS5 com a CaptchaAI: usar socks5h:// em vez de socks5://, para que o DNS seja resolvido no servidor do proxy; autenticar o navegador por biblioteca, não pela linha de comando; e enviar o proxy junto com a tarefa (proxytype=SOCKS5) só quando o formulário avaliar o IP de origem. O resto é encanamento — mostrado aqui em Python, Node.js, Selenium e Puppeteer.

O cenário típico: um time de QA valida um formulário na janela de manutenção, o egress de rede é autorizado e fixo, e a página exibe reCAPTCHA v2. Sem SOCKS5, o teste morre na camada de rede; com SOCKS5 mal configurado, morre por vazamento de DNS — e ninguém entende por que o mesmo script passa na máquina do dev e falha no runner.


SOCKS5 ou proxy HTTP: quando cada um faz sentido

O SOCKS5 encaminha qualquer tráfego TCP/UDP sem reescrever a requisição, evitando os cabeçalhos que um proxy HTTP acrescenta. A escolha depende de duas perguntas: você precisa de WebSocket, e onde o DNS deve ser resolvido?

Característica Proxy HTTP/HTTPS Proxy SOCKS5
Suporte de protocolo Somente HTTP/HTTPS Qualquer TCP/UDP
Modificação de cabeçalho Pode adicionar X-Forwarded-For Sem modificação
Detecção Mais fácil (vazamento de cabeçalhos) Mais difícil
Velocidade Rápido Um pouco mais lento
Autenticação Basic/Digest Usuário e senha
Resolução DNS No cliente No servidor (SOCKS5h)
Suporte WebSocket Limitado Completo

A diferença de latência é pequena: a análise HTTP que o SOCKS5 economiza custa menos que o RTT até o host. Com workers em sa-east-1 e proxy na Europa, a distância pesa muito mais que o protocolo.


Configuração em Python

requests + PySocks

Instale o extra socks do requests, que traz o PySocks:

pip install requests[socks] pysocks

O bloco a seguir faz o ciclo completo: busca a página pelo proxy, extrai a sitekey (chave pública do widget), envia a tarefa e consulta até o token chegar.

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,
    )

Dois detalhes merecem atenção. O socks5h:// do dicionário proxies garante que o domínio seja resolvido pelo servidor do proxy; socks5:// faz o DNS sair pela rede local e é a causa mais comum de divergência entre ambientes. E as chamadas a in.php e res.php seguem pela rota direta: a API não precisa do seu egress. O polling usa intervalo de 5 s com teto de 60 iterações, para que um worker preso não segure a thread.

aiohttp para cargas assíncronas

Se o pipeline já é assíncrono, o aiohttp_socks fornece um connector pronto e evita bloqueio no loop de eventos:

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

O Chrome aceita --proxy-server=socks5://host:porta, mas não aceita credenciais nessa string. Para SOCKS5 autenticado, use o Selenium Wire, que sobe um proxy local e cuida da autenticação. A função abaixo cobre os dois casos:

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()

Com o driver de pé, o fluxo repete o do exemplo em requests: leia a sitekey, envie à CaptchaAI, escreva o token em #g-recaptcha-response e faça o submit. Se o widget usa callback, escrever o token não basta — é preciso disparar a função de callback registrada pelo widget.


Node.js + SOCKS5

No Node, o socks-proxy-agent cria um agent que serve para httpAgent e httpsAgent no Axios. A URL aceita usuário e senha embutidos, o que simplifica em relação ao Chrome:

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

Como no Python, solveCaptcha não usa o agent: as requisições à CaptchaAI seguem pela rota padrão.


Puppeteer + SOCKS5

O Puppeteer herda a limitação do Chrome — --proxy-server não carrega credenciais —, mas page.authenticate() resolve isso no nível da página:

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

Enviando o proxy SOCKS5 na tarefa da CaptchaAI

Alguns formulários avaliam o IP que originou a resolução. Nesses casos, envie o proxy com a tarefa: a CaptchaAI resolve a partir do seu endereço, não do dela. O formato é tipo:host:porta:usuário:senha, com proxytype=SOCKS5:

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

Use esse modo só quando necessário: um proxy lento no caminho aumenta o tempo de resolução e gera mais retentativas.

Sobre threads: os planos são cobrados por thread concorrente, com resoluções ilimitadas no mês. Uma suíte noturna de QA costuma caber em BASIC (US$ 15/mês, 5 threads); pipelines de CI com várias branches em paralelo pedem STANDARD (US$ 30/mês, 15 threads) ou ADVANCE (US$ 90/mês, 50 threads). O que ocupa thread é a tarefa em voo, não a conexão de rede.


Diagnóstico: os erros que aparecem de verdade

Problema Causa Correção
Conexão recusada Porta ou host errado Verifique se o servidor SOCKS5 está em execução
Vazamento de DNS Uso de socks5:// em vez de socks5h:// Use socks5h:// para DNS remoto
Falha na autenticação Credenciais erradas Teste isoladamente com curl --socks5
Conexões lentas Servidor de proxy distante Escolha um proxy geograficamente mais próximo
WebSocket falha O servidor SOCKS5 não suporta UDP Use um servidor SOCKS5 com suporte a UDP

Antes de culpar o CAPTCHA, isole a camada: rode curl --socks5-hostname contra a URL de staging e veja se o HTML volta inteiro. Se chega mas o token é recusado no envio, o problema está na integração e não na rede.

Sobre escopo: mantenha os testes em ambiente próprio ou staging, com dados fictícios, e considere as obrigações da LGPD (RGPD, em Portugal) quando houver dado pessoal nos logs de requisição.


Perguntas frequentes

Qual a diferença prática entre socks5:// e socks5h://?

O h indica que o domínio é resolvido pelo servidor do proxy. Com socks5://, sua máquina resolve o DNS localmente e envia só o IP pelo túnel. Em automação, use sempre socks5h://.

Preciso mandar as chamadas da CaptchaAI pelo proxy também?

Não. O in.php e o res.php funcionam pela rota direta; passá-los pelo proxy só acrescenta latência. O parâmetro proxy no envio é outra coisa: ele diz de qual IP a CaptchaAI deve resolver.

Um proxy SOCKS5 melhora a taxa de resolução?

Não por si só. Ele define de onde a requisição sai; a resolução depende do tipo de CAPTCHA e da qualidade do envio. Um proxy ruim só soma timeout e retentativa. Meça no seu ambiente.

O hCaptcha funciona se eu passar um proxy SOCKS5?

Não. O hCaptcha não é suportado, com ou sem proxy — o mesmo vale para o FunCaptcha e para o GeeTest v4, que consta apenas como em breve. Os tipos cobertos incluem reCAPTCHA v2 e v3, Cloudflare Turnstile e Challenge, GeeTest v3, imagem/OCR e grade, além de CaptchaFox (beta), Friendly Captcha (beta) e Lemin (beta).

Quantas threads a minha suíte precisa se ela usa SOCKS5?

Conte os desafios simultâneos, não os proxies. Se a suíte dispara no máximo cinco formulários ao mesmo tempo, BASIC (US$ 15/mês, 5 threads) atende.


Guias relacionados


Configure o SOCKS5 uma vez e tire o CAPTCHA do caminho da sua suíte — obtenha sua chave de API.

Os comentários estão desativados para este artigo.