Python Selenium 验证码识别:完整示例(2026)
Selenium 运行的是真实的浏览器,页面会正常渲染,脚本也会像在人手操作时那样运行。它唯一无法完成的步骤,就是识别 PopularCaptcha 控件。本指南补上这一步:从渲染后的页面读取 sitekey,用一次 API 调用获取 token,把 token 写入表单,然后提交。
本指南涵盖 PopularCaptcha 控件,Scarnox 目前以无代理方式识别它。请先注册账户,免费试用额度,无需信用卡,并先在测试表单上运行这段脚本。
Selenium 需要做什么
整个流程分为四部分:
- 加载页面,并等待控件渲染完成。
- 从控件中读取
data-sitekey属性。 - 从 API 获取 token,并把它放入表单。
- 在 token 过期之前提交表单。
只有第三步涉及验证码。其余都是常规的 Selenium 操作。
安装依赖包
pip install selenium requests
Selenium 4.6 及更高版本会自动找到匹配的 ChromeDriver,因此你不需要手动下载驱动。
完整脚本
import requests
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.ui import WebDriverWait
API_KEY = "scarnox_YOURAPIKEY"
API_URL = "https://api.scarnox.com/api/tasks/create"
PAGE_URL = "https://example.com/signup"
def solve(sitekey: str, page_url: str, invisible: bool = False) -> str:
body = {
"captcha_type": "PopularCaptchaTaskProxyless",
"site_key": sitekey,
"site_url": page_url,
}
if invisible:
body["is_invisible"] = True
r = requests.post(
API_URL,
headers={"Authorization": f"Bearer {API_KEY}"},
json=body,
timeout=185, # 阻塞直到 token 准备好
)
data = r.json()
if data.get("errorId") != 0:
raise RuntimeError(f"{data.get('errorCode')}: {data.get('errorDescription')}")
return data["solution"]["token"]
INJECT_TOKEN_JS = """
const token = arguments[0];
let field = document.querySelector('[name="h-captcha-response"]');
if (!field) {
field = document.createElement("textarea");
field.name = "h-captcha-response";
field.style.display = "none";
document.querySelector("form").appendChild(field);
}
field.value = token;
let extra = document.querySelector('[name="g-recaptcha-response"]');
if (!extra) {
extra = document.createElement("textarea");
extra.name = "g-recaptcha-response";
extra.style.display = "none";
document.querySelector("form").appendChild(extra);
}
extra.value = token;
"""
def main() -> None:
driver = webdriver.Chrome()
try:
driver.get(PAGE_URL)
widget = WebDriverWait(driver, 15).until(
EC.presence_of_element_located((By.CSS_SELECTOR, "[data-sitekey]"))
)
sitekey = widget.get_attribute("data-sitekey")
invisible = widget.get_attribute("data-size") == "invisible"
token = solve(sitekey, driver.current_url, invisible=invisible)
# 先填写其他字段,再在提交前注入 token,
# 因为 token 约两分钟后过期。
driver.find_element(By.NAME, "email").send_keys("you@example.com")
driver.execute_script(INJECT_TOKEN_JS, token)
driver.find_element(By.CSS_SELECTOR, "form button[type=submit]").click()
WebDriverWait(driver, 15).until(EC.url_changes(PAGE_URL))
print("Submitted. Now at:", driver.current_url)
finally:
driver.quit()
if __name__ == "__main__":
main()
对于无代理的 PopularCaptcha 识别,脚本不需要代理。省略代理字段,让网站看到你正常的网络连接即可。
操作顺序是最容易出错的地方。先填写表单的其余部分,然后识别,然后注入,最后点击。如果你在填写其他字段之前就识别,页面或表单缓慢时,提交可能会超过 token 的有效期。请尽量缩短识别与点击之间的间隔,并且在认为验证码已通过之前,先检查结果页面是否有错误。
为什么用 JavaScript 注入 token
大多数 PopularCaptcha 控件在有人完成验证时,会把 token 写入名为 h-captcha-response 的隐藏文本域。由于 Selenium 看不到真人,脚本需要自己写入同一个字段。INJECT_TOKEN_JS 片段做了两件事:
- 如果控件已经创建了文本域,就复用它。
- 如果页面没有创建,就新建一个并追加到表单中。
它还会填充 g-recaptcha-response,因为许多网站为了兼容性会读取这个名字。
隐形控件
隐形控件没有复选框。它在后台运行,通常在表单提交时触发。脚本会检查 data-size="invisible",看到它时发送 is_invisible: true。有些网站还会给控件附加一个 JavaScript 回调。如果你注入 token 之后表单仍然停留在原处,请查找 data-callback 属性,并用 token 调用该函数。隐形验证码指南涵盖了这种情况。
在测试中使用
Selenium 也是端到端测试的常用工具。如果你自己的预发布网站显示验证码,同样的代码可以让测试通过验证码。请让测试环境与生产环境分开,并且不要对你不拥有的网站运行。测试套件的配置方法见自动化测试中的验证码。
常见问题
- 控件一直不出现。 增加等待时间,或者检查控件是否位于 iframe 中。如果是,请先用
driver.switch_to.frame(...)切换到该 frame。 - 表单提交了,但网站拒绝 token。 检查你是否把 token 发送到了展示控件的那个页面。
driver.current_url必须与页面的真实 URL 一致,包括查询字符串。 - token 过期。 把
solve调用移到更接近提交步骤的位置。token 的有效期约为两分钟。 - API 超时错误。 按脚本中的设置使用约 185 秒的超时时间。重试逻辑见验证码识别错误处理。
定价
你按成功的识别付费,识别失败不收费。费率请查看当前定价,并免费试用额度,无需信用卡,立即注册。