API Tutorials

SOCKS5 代理 + CaptchaAI:设置和配置指南

SOCKS5 和 HTTP 代理最实际的差别不在速度,而在谁做 DNS 解析、请求头会不会被改写、能不能承载 WebSocket。脚本跑在固定出口的代理链路上、又要调用 CaptchaAI 识别 reCAPTCHA v2 或 Turnstile 时,socks5h:// 里那一个字母往往就是“跑通”与“拿不到 token”的分界。

下面按 Python → Selenium → Node.js → Puppeteer 给出四段可直接复制的配置。


先判断:这个场景需不需要 SOCKS5

对比项 HTTP 代理 SOCKS5
协议 仅 HTTP/HTTPS 任意 TCP/UDP
请求头 可能追加 X-Forwarded-For 不改写
DNS 本地解析 可交给代理端
WebSocket 有限 完整

只发普通 HTTP 请求没必要折腾;涉及 WebSocket 长连接、或需要 DNS 也从同一出口走,才换 SOCKS5。


socks5 与 socks5h

  • socks5://:域名在本机解析,IP 再交给代理连接。
  • socks5h://:域名交给代理服务器解析。

差别在于:本机解析会暴露真实解析路径;目标域名若做了地域解析,本机拿到的 IP 与代理出口不在同一地区,页面结构和 sitekey 都可能对不上。没有特殊理由就一律用 socks5h://


Python:requests + PySocks

先装依赖,国内网络可加镜像源参数 -i https://pypi.tuna.tsinghua.edu.cn/simple

pip install requests[socks] pysocks

CaptchaAI 的 in.php / res.php 调用不需要走代理——直连更快也更稳:

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

三点容易忽略:timeout 必须写,SOCKS5 多一层握手,卡死会堵住队列;轮询保持 5 秒间隔;reCAPTCHA 的 token 字段是 g-recaptcha-response,Turnstile 是 cf-turnstile-response

并发场景:aiohttp + 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"))

多条链路时每条建独立的 ProxyConnectorClientSession,共用会发错出口。


Selenium + SOCKS5

Chrome 的 --proxy-server 支持 SOCKS5,但命令行方式不接受用户名密码,需要认证时用 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("--no-sandbox")
    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("--no-sandbox")

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

拿到 token 后写入页面的 #g-recaptcha-response 字段再提交表单即可。


Node.js + SOCKS5

socks-proxy-agent 挂到 axios 上,同样把 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");
}

httpAgenthttpsAgent 要同时设置,只设一个时 HTTP 到 HTTPS 的重定向会悄悄绕开代理,日志里看不出来。


Puppeteer + SOCKS5

启动参数指定代理,认证信息通过 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 容易超时,页面若有长轮询,改成显式等待 [data-sitekey] 更可靠。


把 SOCKS5 代理传给 CaptchaAI

前面的识别请求都是直连。若要让识别与业务请求走同一出口 IP,提交时补上 proxytype:host:port:user:pass)和 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")

这一步不是必选项,先按直连跑通再评估是否需要 IP 对齐。


中文开发者的两套现场

国内站点多用 GeeTest(极验)、网易易盾、腾讯防水墙;CaptchaAI 支持 GeeTest v3,GeeTest v4 官方标注为即将支持、目前不可用,易盾与防水墙不在支持范围。reCAPTCHA 与 Turnstile 主要出现在国际站点,它们要加载 Google 托管脚本,从内地网络访问并不稳定。

另一处工程差异:SOCKS5 出口若在境外,pip install 反而更慢,因为命中不了国内镜像。依赖走本地镜像、业务请求走 SOCKS5 即可。

数据采集请遵守《网络安全法》《数据安全法》《个人信息保护法》与站点的 robots 协议,本文示例统一以自有测试环境为对象。


排错速查表

现象 原因 处理方式
连接被拒绝 端口或主机写错 curl --socks5 单测
DNS 泄漏 用了 socks5:// 改用 socks5h://
认证失败 凭据不对 curl 验证
WebSocket 断开 服务端不支持 UDP 换支持 UDP 的服务端
token 校验不通过 出口 IP 不一致 proxy 参数

CaptchaAI 按线程计费,不按次计费:BASIC $15/月 5 线程,ADVANCE $90/月 50 线程,PREMIUM $170/月 100 线程。代理慢不会多扣费,但会占住线程、拉低吞吐。


常见问题

socks5://socks5h:// 选哪个?

socks5h://。DNS 交给代理服务器解析,既避免本机解析路径外泄,解析结果也与出口地区一致。

CaptchaAI 的识别请求要走代理吗?

默认不需要,直连更快更稳。只有识别请求必须与业务请求同出口 IP 时,才在提交时加 proxyproxytype=SOCKS5

Selenium 用 SOCKS5 为什么认证总失败?

--proxy-server 参数不接受用户名密码。带认证的 SOCKS5 要用 Selenium Wire,把凭据写进 seleniumwire_options

换成 SOCKS5 识别会更快吗?

不会。少一层 HTTP 解析开销而已,对识别流程差异可以忽略,价值在协议覆盖面。


延伸阅读


把 SOCKS5 通道和验证码识别接进同一套脚本,注册 CaptchaAI 获取 API Key

该文章已禁用评论。