AZCaptcha 和 CaptchaAI 都用 2Captcha 兼容的 API 格式,迁移只需换请求地址和 API Key。半小时内能切完,往下看具体步骤。
常见问题
迁移到 CaptchaAI 后计费方式有什么变化?
CaptchaAI 按线程计费,不按识别次数——每个线程可无限次识别,如 BASIC($15/月,5 线程)、ADVANCE($90/月,50 线程)。按并发量选套餐即可。
现有的代理(proxy)配置需要改吗?
不需要。CaptchaAI 用同样的 proxy 和 proxytype 参数,格式一致,原样保留即可。
hCaptcha、GeeTest v4,CaptchaAI 支持吗?
都不支持。CaptchaAI 支持 GeeTest v3;v4 官方状态是"即将支持",还用不了。hCaptcha、FunCaptcha(Arkose Labs)同样不在范围内。
完整迁移一次要花多久?
单个代码库一般 15–30 分钟,主要花在替换请求地址和跑并行测试上;仓库多或类型多,建议拆成几批迁移。
接口与参数对照
请求地址
| 操作 | AZCaptcha | CaptchaAI |
|---|---|---|
| 提交任务 | https://azcaptcha.com/in.php |
https://ocr.captchaai.com/in.php |
| 获取结果 | https://azcaptcha.com/res.php |
https://ocr.captchaai.com/res.php |
| 查询余额 | res.php?action=getbalance |
res.php?action=getbalance |
| 报告识别错误 | res.php?action=reportbad |
res.php?action=reportbad |
参数字段
大多数参数完全一致,需要注意的只有这几处:
| 参数 | AZCaptcha | CaptchaAI | 备注 |
|---|---|---|---|
key |
API Key | API Key | 密钥不同——去 captchaai.com 获取你自己的 |
method |
userrecaptcha |
userrecaptcha |
一致 |
googlekey |
sitekey | sitekey | 一致 |
pageurl |
页面 URL | 页面 URL | 一致 |
json |
1 |
1 |
一致 |
proxy |
user:pass@host:port |
user:pass@host:port |
格式一致 |
proxytype |
HTTP/res.php |
HTTP/res.php |
一致 |
动手迁移:四步就位
第 1 步:注册 CaptchaAI 并拿到 API Key
- 打开 captchaai.com 注册账号
- 给账户充值(CaptchaAI 按线程计费,充值后即可开通线程)
- 从控制台复制你的 API Key
第 2 步:替换请求地址
把域名从 azcaptcha.com 换成 ocr.captchaai.com,其余字段原样保留。CaptchaAI 版本顺带加固:API Key 改从环境变量读取,字段统一用 .get() 兜底。
Python — 之前(AZCaptcha)
import requests
API_KEY = "your_azcaptcha_key"
def solve_recaptcha(sitekey, pageurl):
# Submit
resp = requests.post("https://azcaptcha.com/in.php", data={
"key": API_KEY,
"method": "userrecaptcha",
"googlekey": sitekey,
"pageurl": pageurl,
"json": 1
})
data = resp.json()
if data["status"] != 1:
return {"error": data["request"]}
captcha_id = data["request"]
# Poll
import time
for _ in range(60):
time.sleep(5)
result = requests.get("https://azcaptcha.com/res.php", params={
"key": API_KEY, "action": "get", "id": captcha_id, "json": 1
}).json()
if result["status"] == 1:
return {"solution": result["request"]}
if result["request"] != "CAPCHA_NOT_READY":
return {"error": result["request"]}
return {"error": "TIMEOUT"}
Python — 之后(CaptchaAI)
import os
import time
import requests
API_KEY = os.environ["CAPTCHAAI_API_KEY"] # Changed: use env var
def solve_recaptcha(sitekey, pageurl):
# Submit — only URL changed
resp = requests.post("https://ocr.captchaai.com/in.php", data={
"key": API_KEY,
"method": "userrecaptcha",
"googlekey": sitekey,
"pageurl": pageurl,
"json": 1
})
data = resp.json()
if data.get("status") != 1:
return {"error": data.get("request")}
captcha_id = data["request"]
# Poll — only URL changed
for _ in range(60):
time.sleep(5)
result = requests.get("https://ocr.captchaai.com/res.php", params={
"key": API_KEY, "action": "get", "id": captcha_id, "json": 1
}).json()
if result.get("status") == 1:
return {"solution": result["request"]}
if result.get("request") != "CAPCHA_NOT_READY":
return {"error": result.get("request")}
return {"error": "TIMEOUT"}
JavaScript — 之前(AZCaptcha)
const axios = require("axios");
const API_KEY = "your_azcaptcha_key";
async function solveRecaptcha(sitekey, pageurl) {
const submit = await axios.post("https://azcaptcha.com/in.php", null, {
params: { key: API_KEY, method: "userrecaptcha", googlekey: sitekey, pageurl, json: 1 },
});
if (submit.data.status !== 1) return { error: submit.data.request };
const captchaId = submit.data.request;
for (let i = 0; i < 60; i++) {
await new Promise((r) => setTimeout(r, 5000));
const poll = await axios.get("https://azcaptcha.com/res.php", {
params: { key: API_KEY, action: "get", id: captchaId, json: 1 },
});
if (poll.data.status === 1) return { solution: poll.data.request };
if (poll.data.request !== "CAPCHA_NOT_READY") return { error: poll.data.request };
}
return { error: "TIMEOUT" };
}
JavaScript — 之后(CaptchaAI)
const axios = require("axios");
const API_KEY = process.env.CAPTCHAAI_API_KEY; // Changed: env var
async function solveRecaptcha(sitekey, pageurl) {
// Only URLs changed
const submit = await axios.post("https://ocr.captchaai.com/in.php", null, {
params: { key: API_KEY, method: "userrecaptcha", googlekey: sitekey, pageurl, json: 1 },
});
if (submit.data.status !== 1) return { error: submit.data.request };
const captchaId = submit.data.request;
for (let i = 0; i < 60; i++) {
await new Promise((r) => setTimeout(r, 5000));
const poll = await axios.get("https://ocr.captchaai.com/res.php", {
params: { key: API_KEY, action: "get", id: captchaId, json: 1 },
});
if (poll.data.status === 1) return { solution: poll.data.request };
if (poll.data.request !== "CAPCHA_NOT_READY") return { error: poll.data.request };
}
return { error: "TIMEOUT" };
}
国内团队提示: CI 在大陆网络内,装依赖可用清华 TUNA 镜像加速。
第 3 步:封装一层 provider 抽象
不想一次性硬切,可以先包一个与具体服务商无关的 wrapper,出问题时改一行就能回滚:
import os
import time
import requests
class CaptchaProvider:
def __init__(self, base_url, api_key):
self.submit_url = f"{base_url}/in.php"
self.result_url = f"{base_url}/res.php"
self.api_key = api_key
self.session = requests.Session()
def solve(self, sitekey, pageurl, method="userrecaptcha"):
resp = self.session.post(self.submit_url, data={
"key": self.api_key,
"method": method,
"googlekey": sitekey,
"pageurl": pageurl,
"json": 1
})
data = resp.json()
if data.get("status") != 1:
return {"error": data.get("request")}
captcha_id = data["request"]
for _ in range(60):
time.sleep(5)
result = self.session.get(self.result_url, params={
"key": self.api_key, "action": "get",
"id": captcha_id, "json": 1
}).json()
if result.get("status") == 1:
return {"solution": result["request"]}
if result.get("request") != "CAPCHA_NOT_READY":
return {"error": result.get("request")}
return {"error": "TIMEOUT"}
# Switch by changing one line:
# provider = CaptchaProvider("https://azcaptcha.com", "old_key")
provider = CaptchaProvider(
"https://ocr.captchaai.com",
os.environ["CAPTCHAAI_API_KEY"]
)
第 4 步:跑并行测试,用数字说话
两个 provider 同时跑,拿真实数据对比,而不是凭感觉判断:
def parallel_test(sitekey, pageurl, runs=10):
azcaptcha = CaptchaProvider("https://azcaptcha.com", "old_key")
captchaai = CaptchaProvider(
"https://ocr.captchaai.com",
os.environ["CAPTCHAAI_API_KEY"]
)
results = {"azcaptcha": [], "captchaai": []}
for i in range(runs):
start = time.time()
az_result = azcaptcha.solve(sitekey, pageurl)
results["azcaptcha"].append({
"success": "solution" in az_result,
"time": time.time() - start
})
start = time.time()
cai_result = captchaai.solve(sitekey, pageurl)
results["captchaai"].append({
"success": "solution" in cai_result,
"time": time.time() - start
})
for provider, data in results.items():
successes = sum(1 for r in data if r["success"])
avg_time = sum(r["time"] for r in data) / len(data)
print(f"{provider}: {successes}/{runs} success, {avg_time:.1f}s avg")
上线检查与常见报错
迁移检查清单
| 步骤 | 状态 |
|---|---|
| 创建 CaptchaAI 账号并充值 | ☐ |
| 替换所有文件里的请求地址 | ☐ |
| 更新 API Key(改用环境变量) | ☐ |
| 跑并行测试(至少 10 次识别) | ☐ |
| 对比成功率 | ☐ |
| 对比识别耗时 | ☐ |
| 更新新接口的监控和告警规则 | ☐ |
| 切换生产流量 | ☐ |
| 观察 24 小时 | ☐ |
| 停用 AZCaptcha 的 API Key | ☐ |
常见报错排查
| 报错 | 原因 | 处理方式 |
|---|---|---|
ERROR_KEY_DOES_NOT_EXIST |
API Key 填错了 | 去控制台核对 CaptchaAI 的 API Key |
ERROR_ZERO_BALANCE |
新账户还没充值 | 在 captchaai.com 充值 |
| 报错码对不上 | 两家的错误码有细微差异 | 对照错误码表逐个映射,绝大部分是通用的 |
| 识别成功率不一样 | 两边的识别模型和资源池不同 | 至少跑 50 次识别再比较,样本太小会有偏差 |
下一步
想要更快、更稳定的识别体验?获取你的 CaptchaAI API Key,照上面四步走,几十分钟切完生产流量。
相关阅读:
- 接口映射与竞品对照
- 并行测试实操指南
- 团队为什么要换验证码服务商