Integrations

Bright Data + CaptchaAI:完整的代理集成指南

换了住宅 IP,验证码怎么还在弹?因为代理和识别是两层:Bright Data(原 Luminati,7200 万+住宅 IP)负责换 IP,真弹出 reCAPTCHA v2 或 Turnstile 时还是要 CaptchaAI 拿 token。跨境电商团队抓美区、欧区商品数据常用这个组合:定向换 IP,命中验证码就转交 CaptchaAI。


代理和验证码识别,谁负责什么

Your Script ──▶ Bright Data Proxy ──▶ Target Site
                                          │
                                    CAPTCHA appears
                                          │
                                    CaptchaAI API ──▶ Solved token
                                          │
                            Inject token ◀─┘

CaptchaAI 不经过你的代理,用自己的服务器识别。代理管抓取,CaptchaAI 管识别:

  • 代理层:换 IP、做地区定向,降低触发率。
  • 识别层:验证码弹出后,把 sitekey 和页面 URL 交给 CaptchaAI,拿回 token。

Python 集成:从抓取到自动识别验证码

Requests + Bright Data + CaptchaAI

import requests
import time

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

# Bright Data proxy credentials
BRIGHT_DATA_PROXY = {
    "http": "http://brd-customer-CUSTOMER_ID-zone-ZONE:[email protected]:22225",
    "https": "http://brd-customer-CUSTOMER_ID-zone-ZONE:[email protected]:22225",
}


def fetch_with_proxy(url):
    """Fetch a page through Bright Data proxy."""
    resp = requests.get(
        url,
        proxies=BRIGHT_DATA_PROXY,
        headers={
            "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
            "AppleWebKit/537.36 (KHTML, like Gecko) "
            "Chrome/126.0.0.0 Safari/537.36"
        },
        timeout=30,
    )
    return resp


def solve_recaptcha(site_url, sitekey):
    """Solve reCAPTCHA v2 via CaptchaAI."""
    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("Solve timeout")


def solve_turnstile(site_url, sitekey):
    """Solve Cloudflare Turnstile via CaptchaAI."""
    resp = requests.post(f"{CAPTCHAAI_URL}/in.php", data={
        "key": CAPTCHAAI_KEY,
        "method": "turnstile",
        "sitekey": sitekey,
        "pageurl": site_url,
        "json": 1,
    })
    data = resp.json()
    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("Solve timeout")

Selenium + Bright Data + CaptchaAI

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

BRIGHT_DATA_HOST = "brd.superproxy.io"
BRIGHT_DATA_PORT = 22225
BRIGHT_DATA_USER = "brd-customer-CUSTOMER_ID-zone-residential"
BRIGHT_DATA_PASS = "PASSWORD"


def create_driver_with_proxy():
    options = webdriver.ChromeOptions()
    options.add_argument(
        f"--proxy-server=http://{BRIGHT_DATA_HOST}:{BRIGHT_DATA_PORT}"
    )
    options.add_argument("--no-sandbox")
    options.add_argument("--window-size=1920,1080")

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


def scrape_with_captcha_solving(url, sitekey=None):
    driver = create_driver_with_proxy()

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

        # Auto-detect sitekey if not provided
        if not sitekey:
            sitekey = driver.execute_script(
                "return document.querySelector('[data-sitekey]')"
                "?.getAttribute('data-sitekey')"
            )

        if sitekey:
            token = solve_recaptcha(url, sitekey)

            driver.execute_script(f"""
                document.querySelector('#g-recaptcha-response').value = '{token}';
                document.querySelectorAll('[name="g-recaptcha-response"]')
                    .forEach(el => {{ el.value = '{token}'; }});
            """)

            # Trigger callback
            driver.execute_script("""
                if (typeof ___grecaptcha_cfg !== 'undefined') {
                    const clients = ___grecaptcha_cfg.clients;
                    for (const key in clients) {
                        for (const prop in clients[key]) {
                            const val = clients[key][prop];
                            if (val && typeof val === 'object') {
                                for (const p in val) {
                                    if (typeof val[p]?.callback === 'function') {
                                        val[p].callback(arguments[0]);
                                    }
                                }
                            }
                        }
                    }
                }
            """)

        return driver.page_source

    finally:
        driver.quit()

两段代码走的是同一套流程:

  • 拉取目标页面;
  • 提取 sitekey
  • 转交 CaptchaAI 识别,拿到 token;
  • 把 token 注入表单字段并提交。

按国家/地区定向抓取,降低验证码触发率

Bright Data 支持按国家、州、城市三级定向:

# Country targeting
proxy_us = "http://brd-customer-ID-zone-residential-country-us:[email protected]:22225"
proxy_uk = "http://brd-customer-ID-zone-residential-country-gb:[email protected]:22225"
proxy_de = "http://brd-customer-ID-zone-residential-country-de:[email protected]:22225"

# City targeting
proxy_nyc = "http://brd-customer-ID-zone-residential-country-us-city-newyork:[email protected]:22225"

# Use the geo-matched proxy for lower CAPTCHA rates
def scrape_localized(url, country="us"):
    proxy = f"http://brd-customer-ID-zone-residential-country-{country}:[email protected]:22225"
    resp = requests.get(url, proxies={"http": proxy, "https": proxy}, timeout=30)
    return resp

抓美区用美区 IP、抓欧区用欧区 IP,归属地对上号,比换更贵的代理类型划算。


会话保持:粘性会话还是轮换 IP?

# Sticky session (same IP for entire session)
proxy_sticky = (
    "http://brd-customer-ID-zone-residential"
    "-session-abc123:[email protected]:22225"
)

# Rotating (new IP each request)
proxy_rotating = (
    "http://brd-customer-ID-zone-residential:[email protected]:22225"
)

验证码流程用粘性会话,同一 IP 从加载用到提交——token 和 IP 绑定,中途换 IP 会被拒绝。纯翻页任务才适合轮换 IP。


Node.js 集成

const axios = require("axios");
const https = require("https");

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

const proxyAgent = new (require("https-proxy-agent"))(
  "http://brd-customer-ID-zone-residential:[email protected]:22225"
);

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

async function solveCaptcha(siteUrl, sitekey) {
  const submit = await axios.post(`${CAPTCHAAI_URL}/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(`${CAPTCHAAI_URL}/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");
}

Node.js 版本调用逻辑跟 Python 一致:先取 sitekey,再交给 CaptchaAI 识别,拿到 token 后注入表单。


该选哪种代理类型,区域参数怎么配

先定类型,再配区域参数:

类型 IP 数量 速度 成本 触发率
数据中心 77 万+ 较高
住宅 7200 万+ 中等 中等 较低
ISP 70 万+ 最低
移动网络 700 万+ 很低

验证码较多的站点优先选住宅或 ISP 类型;数据中心 IP 便宜快,但更容易被标记。类型定好后,区域参数照下表配置:

配置项 推荐值 原因
代理类型 住宅 触发率最低
地区定位 匹配目标站点所在地 IP 与内容地区一致
会话类型 粘性会话 token 需与 IP 匹配
IP 质量过滤 高质量 避开已标记 IP
最大并发数 100+ 支持并行识别任务

常见故障怎么排查

代理返回 407

凭证错误。检查 customer ID、zone、密码。

每次请求都弹验证码

命中了数据中心 IP。切换到住宅或 ISP 区域。

token 被拒绝

识别和提交之间 IP 变了。改用粘性会话。

响应变慢

出口节点拥塞。定向访问量较小的地区。

连接被拒绝

触碰带宽上限。登录控制台查看用量。


常见问题

明明用了住宅 IP,验证码为什么还是弹出来?

住宅 IP 只降触发率,不是完全不触发。稳定做法是两层都做:代理降触发率,CaptchaAI 兜底识别。

国内团队抓国外站点,reCAPTCHA 要注意什么?

reCAPTCHA 加载 Google 托管脚本,国内网络访问不稳定,常表现为组件不渲染。先判断是网络问题还是真触发验证码,Turnstile 没有这层依赖,排查更简单。

该用粘性会话还是轮换 IP?

验证码请求用粘性会话,token 和 IP 绑定,中途换 IP 会被拒绝。只有翻页任务适合轮换 IP。

多线程并发抓取,代理会话怎么分配?

建议一个线程对应一个独立粘性会话(用不同 session 参数区分),避免多线程共用同一 IP,也方便按线程排查问题。


相关阅读


把 Bright Data 的代理网络和自动验证码识别接在一起——获取你的 CaptchaAI API Key,把抓取流程跑稳定。

该文章已禁用评论。