移动浏览器自动化遇到与桌面相同的验证码 - reCAPTCHA 复选框、Cloudflare 挑战、图像网格 - 但也面临移动特定的怪癖,例如响应式布局、仅触摸交互和不同的用户代理特征。CaptchaAI无论设备上下文如何,都会处理求解。
本教程涵盖两种方法:通过 ADB 使用 Selenium 和 Chrome for Android,以及 Playwright 在桌面上的移动模拟。
真实场景
您正在为 reCAPTCHA v2 提供服务的移动优化网站上自动提交表单。该站点检测移动用户代理并呈现移动特定的验证码布局。您需要解决验证码并从移动浏览器上下文提交表单。
方法 1:Playwright 移动仿真 (Python)
Playwright 的设备模拟是通过验证码解决实现移动浏览器自动化的最简单方法 - 无需物理设备:
# playwright_mobile_captcha.py
import asyncio
import httpx
from playwright.async_api import async_playwright
API_KEY = "YOUR_API_KEY"
async def solve_recaptcha(sitekey: str, pageurl: str) -> str:
"""Submit reCAPTCHA v2 to CaptchaAI and poll for result."""
async with httpx.AsyncClient(timeout=180) as client:
# Submit task
resp = await client.get(
"https://ocr.captchaai.com/in.php",
params={
"key": API_KEY,
"method": "userrecaptcha",
"googlekey": sitekey,
"pageurl": pageurl,
"json": "1",
},
)
result = resp.json()
if result["status"] != 1:
raise Exception(f"Submit failed: {result['request']}")
task_id = result["request"]
# Poll for result
for _ in range(30):
await asyncio.sleep(5)
poll = await client.get(
"https://ocr.captchaai.com/res.php",
params={
"key": API_KEY,
"action": "get",
"id": task_id,
"json": "1",
},
)
poll_result = poll.json()
if poll_result["status"] == 1:
return poll_result["request"]
if poll_result["request"] != "CAPCHA_NOT_READY":
raise Exception(f"Solve failed: {poll_result['request']}")
raise Exception("Polling timeout")
async def main():
async with async_playwright() as p:
# Launch with iPhone 13 emulation
iphone = p.devices["iPhone 13"]
browser = await p.chromium.launch(headless=False)
context = await browser.new_context(**iphone)
page = await context.new_page()
await page.goto("https://example.com/mobile-form")
await page.wait_for_selector(".g-recaptcha", timeout=10000)
# Extract sitekey
sitekey = await page.get_attribute(".g-recaptcha", "data-sitekey")
pageurl = page.url
print(f"Found sitekey: {sitekey}")
# Solve via CaptchaAI
token = await solve_recaptcha(sitekey, pageurl)
print(f"Token received: {token[:50]}...")
# Inject token
await page.evaluate(f"""
document.getElementById('g-recaptcha-response').value = '{token}';
document.getElementById('g-recaptcha-response').style.display = '';
""")
# Trigger callback if it exists
await page.evaluate(f"""
try {{
const clients = ___grecaptcha_cfg.clients;
Object.keys(clients).forEach(k => {{
Object.keys(clients[k]).forEach(j => {{
if (clients[k][j] && clients[k][j].callback) {{
clients[k][j].callback('{token}');
}}
}});
}});
}} catch(e) {{}}
""")
# Submit form
await page.click('button[type="submit"]')
await page.wait_for_load_state("networkidle")
print("Form submitted successfully")
await browser.close()
asyncio.run(main())
方法 2:Selenium 与移动仿真 (JavaScript)
将 Selenium 与 Chrome DevTools Protocol 移动模拟结合使用以实现 Node.js 工作流程:
// selenium_mobile_captcha.js
const { Builder, By, until } = require('selenium-webdriver');
const chrome = require('selenium-webdriver/chrome');
const axios = require('axios');
const API_KEY = 'YOUR_API_KEY';
async function solveCaptcha(sitekey, pageurl) {
// Submit task
const submitResp = await axios.get('https://ocr.captchaai.com/in.php', {
params: {
key: API_KEY,
method: 'userrecaptcha',
googlekey: sitekey,
pageurl: pageurl,
json: '1',
},
});
if (submitResp.data.status !== 1) {
throw new Error(`Submit failed: ${submitResp.data.request}`);
}
const taskId = submitResp.data.request;
// Poll for result
for (let i = 0; i < 30; i++) {
await new Promise((r) => setTimeout(r, 5000));
const pollResp = await axios.get('https://ocr.captchaai.com/res.php', {
params: { key: API_KEY, action: 'get', id: taskId, json: '1' },
});
if (pollResp.data.status === 1) return pollResp.data.request;
if (pollResp.data.request !== 'CAPCHA_NOT_READY') {
throw new Error(`Solve failed: ${pollResp.data.request}`);
}
}
throw new Error('Polling timeout');
}
async function main() {
// Configure mobile emulation
const mobileEmulation = {
deviceMetrics: { width: 390, height: 844, pixelRatio: 3.0 },
userAgent:
'Mozilla/5.0 (iPhone; CPU iPhone OS 16_0 like Mac OS X) ' +
'AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.0 Mobile/15E148 Safari/604.1',
};
const options = new chrome.Options();
options.setMobileEmulation(mobileEmulation);
const driver = await new Builder()
.forBrowser('chrome')
.setChromeOptions(options)
.build();
try {
await driver.get('https://example.com/mobile-form');
await driver.wait(until.elementLocated(By.css('.g-recaptcha')), 10000);
// Extract sitekey
const captchaEl = await driver.findElement(By.css('.g-recaptcha'));
const sitekey = await captchaEl.getAttribute('data-sitekey');
const pageurl = await driver.getCurrentUrl();
console.log(`Sitekey: ${sitekey}`);
// Solve CAPTCHA
const token = await solveCaptcha(sitekey, pageurl);
console.log(`Token: ${token.substring(0, 50)}...`);
// Inject token
await driver.executeScript(`
document.getElementById('g-recaptcha-response').value = arguments[0];
`, token);
// Submit form
await driver.findElement(By.css('button[type="submit"]')).click();
console.log('Form submitted');
} finally {
await driver.quit();
}
}
main().catch(console.error);
特定于移动设备的注意事项
| 因素 | 桌面 | 移动的 | 对验证码的影响 |
|---|---|---|---|
| 用户代理 | 桌面版 Chrome/Firefox | 移动Safari/Chrome | 某些站点按设备提供不同的验证码配置 |
| 视口 | 1920年×1080+ | 390×844 | CAPTCHA 小部件可能会以不同方式呈现 |
| 触摸事件 | 鼠标事件 | 触摸事件 | 一些验证码验证交互类型 |
| 网络 | 宽带 | 4G/5G | 可能需要更长的超时时间 |
故障排除
| 问题 | 原因 | 处理方式 |
|---|---|---|
| 验证码未在移动仿真中呈现 | 站点通过 navigator.platform 检测仿真 | 在 DevTools 协议中设置平台覆盖 |
g-recaptcha-response 文本区域未找到 |
移动布局使用不同的验证码渲染 | 按名称属性而不是 ID 搜索文本区域 |
| token 提交有效,但表单仍然失败 | 服务器验证用户代理一致性 | 确保使用相同的 User-Agent 进行求解和表单提交 |
| 模拟中页面加载缓慢 | 资源密集型页面 | 使用--disable-images Chrome标志来加速加载 |
常问问题
我应该使用真实的移动设备还是模拟器?
仿真的开发速度更快,CI/CD. 通过 Appium 或 ADB 的真实设备更适合特征采集很重要的生产场景。
CaptchaAI 需要知道它是移动验证码吗?
不会。CaptchaAI 根据sitekey 和页面URL 来解决。移动设备与桌面设备的区别不会影响解决过程。
我可以将移动模拟与代理结合使用吗?
是的。 Playwright 和 Selenium 都支持代理配置和移动模拟。为了保持一致性,还将代理传递给 CaptchaAI。
相关文章
- 如何使用Api解决Recaptcha V2回调
- Zapier 验证码无代码自动化
- Recaptcha V2 Turnstile同一站点处理
下一步
开始自动化移动验证码流程 –”获取您的 CaptchaAI API 密钥并与您的移动自动化堆栈集成。
相关指南:
- 使用 Appium 进行移动应用自动化中的验证码处理
- React Native WebView 验证码解决
- 从页面源中提取 reCAPTCHA 参数