如何将 MobileProxy.Space 代理与 CAPTCHA 识别结合,打造稳定的自动化工作流
大多数自动化项目失败,并不是因为代码写得差,而是因为两件与解析逻辑无关的事: IP 信誉 和 CAPTCHA。
你写好一个干净的爬虫,本地测试一切正常。然后扩到 20 个线程,突然就出现 403、没完没了的「verify you are human」页面,以及空结果。常见反应是多买代理,其次是买 CAPTCHA 识别服务。但真正的解法是让两者 作为同一套系统协同工作。
本教程将演示如何把 来自 MobileProxy.Space 的移动代理与自动化 CAPTCHA 识别 API 连接起来,让工作流能撑住长时间运行——包含代码示例、重试逻辑,以及那些会悄悄拖垮成功率的错误清单。来自 MobileProxy.Space 的移动代理与自动化 CAPTCHA 识别 API 连接起来,让工作流能撑住长时间运行——包含代码示例、重试逻辑,以及那些会悄悄拖垮成功率的错误清单。
为什么仅有代理不够
移动代理是自动化中最强的选择,因为移动 IP 会通过运营商 NAT 被数百名真实用户共享。对某个地址过度封锁会伤害真实客户,因此反爬系统对移动网段通常更宽容。
但宽容不等于免疫。即便有完美的移动 IP,你仍会在以下情况遇到 CAPTCHA:
- 请求发送速度快过真人;
- 浏览器指纹看起来像自动化;
- 目标网站在特定路由上对 所有人 展示 CAPTCHA(登录、结账、搜索);
- 会话 cookie 缺失或不一致。
为什么仅有 CAPTCHA 识别服务也不够
反过来看。假设你只用数据中心 IP 上的识别服务,会发生什么?
- reCAPTCHA v3 返回低分,网站即使拿到「有效」token 也会拒绝;
- 刚解完一道 CAPTCHA,立刻又出现新的;
- token 校验失败,因为请求 CAPTCHA 的 IP 与提交 token 的 IP 不一致。
关键原则: 代理降低的是 CAPTCHA 出现频率。识别服务处理仍然出现的那些情况。两者都需要,并且必须共享同一会话上下文。
架构
稳定工作流遵循的循环如下:
┌──────────────┐
│ Task queue │
└──────┬───────┘
│
▼
┌────────────────────┐ ┌──────────────────────┐
│ Worker (session) │────▶│ MobileProxy.Space │
│ cookies + UA │ │ mobile IP + rotation │
└──────┬─────────────┘ └──────────────────────┘
│
│ CAPTCHA detected?
▼
┌────────────────────────┐
│ CAPTCHA solving API │──▶ token
└──────┬─────────────────┘
│
▼
┌────────────────────┐
│ Submit + validate │──▶ success / rotate IP / retry
└────────────────────┘
步骤 1. 准备移动代理
在 MobileProxy.Space 控制台中,你会得到具备以下信息的代理:
- 主机与端口(HTTP/HTTPS 与 SOCKS5 端口分开);
- 登录名与密码,用于授权;
- 一个 IP 轮换链接——调用该 URL 可强制更换移动 IP;
- 可选的 自动轮换间隔(例如每 5–15 分钟);
- 地理选择,使代理国家与网站目标受众匹配。
对自动化最关键的两项设置:
1. 轮换模式。 对逻辑驱动工作流使用 通过链接手动轮换(仅在被封时轮换)。对广泛、无状态爬取使用 定时轮换。
2. 轮换间隔。 如果登录流程进行中却每 60 秒轮换一次,你会自己打断会话。间隔应长于最长的单次任务。
写任何逻辑前先做快速自检:
curl -x http://LOGIN:PASSWORD@proxy.host:PORT https://api.ipify.org
# → returns the current mobile IP
curl "https://mobileproxy.space/api.html?command=reboot&proxy_key=YOUR_KEY"
# → forces IP rotation (use your actual rotation link from the dashboard)
curl -x http://LOGIN:PASSWORD@proxy.host:PORT https://api.ipify.org
# → should return a different IP
如果 IP 没有变化,请 先 解决这个问题,再调试其他内容。
步骤 2. 将客户端绑定到同一会话身份
一个会话 = 一个代理 + 一个 cookie jar + 一个 User-Agent + 一组请求头。绝不要混用。
Python requests
import requests
PROXY = "http://LOGIN:PASSWORD@proxy.host:PORT"
session = requests.Session()
session.proxies = {"http": PROXY, "https": PROXY}
session.headers.update({
"User-Agent": ("Mozilla/5.0 (Linux; Android 13; SM-S918B) "
"AppleWebKit/537.36 (KHTML, like Gecko) "
"Chrome/121.0.0.0 Mobile Safari/537.36"),
"Accept-Language": "en-US,en;q=0.9",
})
一个小但关键的细节:如果你使用 移动 代理,就使用 移动 User-Agent 和移动视口。运营商 IP 上使用桌面 Chrome UA,是指纹系统会注意到的不一致。
Playwright
from playwright.sync_api import sync_playwright
with sync_playwright() as p:
browser = p.chromium.launch(
proxy={
"server": "http://proxy.host:PORT",
"username": "LOGIN",
"password": "PASSWORD",
}
)
context = browser.new_context(
user_agent=("Mozilla/5.0 (Linux; Android 13; SM-S918B) "
"AppleWebKit/537.36 (KHTML, like Gecko) "
"Chrome/121.0.0.0 Mobile Safari/537.36"),
viewport={"width": 412, "height": 915},
is_mobile=True,
has_touch=True,
locale="en-US",
)
page = context.new_page()
page.goto("https://example.com")
步骤 3. 加入自动 CAPTCHA 识别
出现 CAPTCHA 时,worker 需要的是 token,而不是人。这时就要用基于 API 的识别服务:你发送 CAPTCHA 参数,拿回 token 或文本,并在同一请求流中提交。
本教程使用 CapMonster Cloud——一款 AI CAPTCHA 识别器,可通过简单的两次调用 API 处理 reCAPTCHA v2/v3、Cloudflare Turnstile、图片验证码及其他常见类型。对我们来说,关键的是它支持 绑定代理的任务(proxy-bound tasks),这正是使用移动 IP 时所需要的。
理解两种任务模式
经验法则: 如果网站在意分数或会话,就把 MobileProxy.Space 凭据传入任务。
提取 sitekey
在开始识别前,先从页面获取 sitekey:
import re
html = session.get("https://target-site.com/login").text
match = re.search(r'data-sitekey="([^"]+)"', html)
sitekey = match.group(1) if match else None
在 Playwright 中:
sitekey = page.get_attribute("[data-sitekey]", "data-sitekey")
创建任务并轮询
import time, requests
API = "https://api.capmonster.cloud"
CLIENT_KEY = "YOUR_CLIENT_KEY"
def solve_recaptcha_v2(website_url, sitekey, proxy=None):
if proxy:
task = {
"type": "RecaptchaV2Task",
"websiteURL": website_url,
"websiteKey": sitekey,
"proxyType": "http",
"proxyAddress": proxy["host"],
"proxyPort": proxy["port"],
"proxyLogin": proxy["login"],
"proxyPassword": proxy["password"],
}
else:
task = {
"type": "RecaptchaV2TaskProxyless",
"websiteURL": website_url,
"websiteKey": sitekey,
}
r = requests.post(f"{API}/createTask",
json={"clientKey": CLIENT_KEY, "task": task},
timeout=30).json()
if r.get("errorId"):
raise RuntimeError(r.get("errorCode"))
task_id = r["taskId"]
for _ in range(40): # ~2 minutes max
time.sleep(3)
res = requests.post(f"{API}/getTaskResult",
json={"clientKey": CLIENT_KEY, "taskId": task_id},
timeout=30).json()
if res.get("status") == "ready":
return res["solution"]["gRecaptchaResponse"]
if res.get("errorId"):
raise RuntimeError(res.get("errorCode"))
raise TimeoutError("CAPTCHA task timed out")
然后将 token 注入表单,并 通过同一会话和同一代理提交:
token = solve_recaptcha_v2("https://target-site.com/login", sitekey, PROXY_CFG)
resp = session.post("https://target-site.com/login", data={
"username": "user",
"password": "pass",
"g-recaptcha-response": token,
})
对于浏览器自动化,把 token 写入 DOM 并触发网站回调:
page.evaluate("""(token) => {
document.querySelector('[name="g-recaptcha-response"]').value = token;
}""", token)
page.click("button[type=submit]")
如果不想自己写轮询逻辑,可在 CapMonster 文档中找到面向 Python、Node.js、C# 和浏览器扩展的官方 SDK 与集成指南。
步骤 4. 粘合逻辑:何时轮换,何时识别
稳定性真正来自这里。把每次响应当作信号,并据此反应。
def handle(response, ctx):
if response.status_code == 200 and not has_captcha(response.text):
return "OK"
if has_captcha(response.text):
ctx["captcha_count"] += 1
# solve first, rotate only if solving keeps failing
if ctx["captcha_count"] <= 2:
return "SOLVE"
return "ROTATE_AND_RETRY"
if response.status_code in (403, 429):
return "ROTATE_AND_RETRY"
if response.status_code >= 500:
return "BACKOFF_RETRY"
return "FAIL"
实践中有效的轮换规则
- 切勿在流程中途轮换。 在「加载 CAPTCHA」与「提交 token」之间轮换会使 token 失效。
- 在连续 N 次封锁后再轮换,而不是每次出错都轮换。
- 轮换时重置会话。 新 IP → 新 cookie jar → 新 UA。全新移动 IP 上带回旧 cookie 会显得异常。
- 加入抖动(jitter)。 在请求之间 sleep random.uniform(1.5, 4.0),而不是固定延迟。
- 限制每个 IP 的并发。 一个移动 IP 跑 50 个并行线程本身就是一种指纹。每个代理 3–8 个并发请求是合理起点。
import random, time
def rotate(ctx):
requests.get(ROTATION_LINK, timeout=60)
time.sleep(random.uniform(8, 15)) # let the carrier assign a new IP
ctx["session"] = new_session() # fresh cookies + headers
ctx["captcha_count"] = 0
步骤 5. 衡量真正重要的指标
每次运行记录这四项指标——它们能准确告诉你哪一层在失败:
有用诊断:如果 CAPTCHA 比率高, 但 识别成功率也高,说明代理与节奏需要改进。如果 CAPTCHA 比率低但识别成功率差,说明 token 提交逻辑或代理绑定有问题。
常见陷阱清单
- ❌ 在移动代理上使用桌面 User-Agent
- ❌ 把 websiteURL 写成 API 端点而不是页面 URL
- ❌ 在一个 IP 上识别 CAPTCHA,却从另一个 IP 提交
- ❌ 重复使用 token(一次性且寿命短)
- ❌ 轮询循环没有超时 → worker 挂起
- ❌ 每次出错都轮换 IP,浪费 IP 与会话
- ❌ 忽略 Accept-Language / 时区与代理地理不匹配
- ❌ 硬编码会被网站轮换的 sitekey
小案例:稳定价格监控任务
某团队每天抓取约 35,000 个商品页,成功率仅 61%。他们的配置:数据中心代理、固定 1 秒延迟、无代理 CAPTCHA 识别。
改动内容:
- 改用移动代理,并以 由封锁信号触发的手动轮换 替代定时器。
- 将移动 UA + 视口 + is_mobile 与代理类型匹配。
- 将分数敏感端点切换为 绑定代理的识别任务。
- 加入 1.5–4 秒随机延迟,并将每 IP 并发限制为 6。
- 对 5xx 增加指数退避重试。
一周后结果:成功率 94%,CAPTCHA 比率从 23% 降到 6%,识别费用反而 下降——因为一开始出现的 CAPTCHA 就更少了。
这就是重点:代理与 CAPTCHA 识别不是互相竞争的成本项。更好的代理会降低识别账单,而可靠的识别服务能避免代理浪费在无效重试上。
最终部署清单
- 通过 curl 验证代理 + 已测试轮换链接
- 轮换间隔长于最长单次任务
- 一个会话 = 一个代理 + 一个 cookie jar + 一套指纹
- 移动 IP 使用移动 UA 与视口
- 动态提取 sitekey,不硬编码
- 分数敏感流程使用绑定代理的识别任务
- 每次识别调用都有超时与重试上限
- 对四项核心指标做结构化日志
- 优雅降级:把任务重新入队,而不是直接丢弃
把循环搭建一次,记录一切,用数据而不是猜测来调优。这样脆弱脚本才会变成你可以放心通宵运行的自动化工作流。





