
Anh Tuan
Data Science Expert
已发表 Oct 22, 2026
已更新 Oct 22, 2026 · 最小阅读量

当浏览器代理被 CAPTCHA 打断时,它需要有用的信息。仅有页面标题或截图,并不足以让代理知道当前是哪一类 CAPTCHA,或者下一步所需的参数是什么。返回一个小而结构化的结果,可以在应用请求求解之前,为其提供一个清晰的决策点。
Haystack 是一个用于构建 AI 应用、检索流水线和代理的 Python 框架。它的原生工具可以包装这些应用所用到的函数。本指南将 Haystack 工具与 CapSolver 连接起来,完成一个特定任务:检查当前浏览器页面并返回 CAPTCHA 参数。示例使用的是开发页面,不会发送任何付费求解请求。它为你提供了一个可用的“检测组件”,可以放在一个单独授权的求解步骤之前。
CAPTCHA 检测工具应该位于“浏览器到达验证检查点的动作”和“决定如何处理该检查点的代码”之间。浏览器仍然负责导航和维护当前页面。Haystack 提供工具接口,而 Core SDK 用于读取受支持的 CAPTCHA 信息。
例如,一个测试自己表单的团队,可以让浏览器访问该表单,调用检测工具,然后检查返回的类型和站点密钥。测试框架接着可以选择官方测试密钥路径,或者一个单独配置的求解检查。它不应该把 CAPTCHA 控件本身当作表单的业务内容。
这是一个基于 Haystack 文档化的 Tool 抽象 的开发者集成,而不是所谓“官方 Haystack 插件”的声明。该工具目标非常狭窄,而且运行时不需要 LLM。直接调用它,在添加模型驱动的工具选择之前就已很有价值。
你需要 Python、Haystack 包、带 Playwright 依赖的 CapSolver Core SDK,以及为 Playwright 安装好的 Chromium。下面示例使用 Python 3.12、haystack-ai 3.4.0、capsolver-core 0.1.1 和 Playwright 1.64.0。这些是已测试过的版本,而不是最新发行版的声明。
浏览器必须能加载 Google 的公共 reCAPTCHA 脚本。本地页面使用的是 Google 文档中的开发站点密钥;它不是生产密钥,不能用于生产部署。Google 的 reCAPTCHA 测试指南 解释了测试密钥与生产验证之间的区别。
本检测示例不需要 CapSolver API 密钥或模型提供方的密钥。后续的求解操作则需要有效的 CapSolver 账户密钥。后续基于 LLM 的 Haystack Agent 需要单独配置自己的模型提供方。这是分开的前置条件,所以不要试图通过修改 CAPTCHA 参数来排查“缺少模型凭据”的错误。
创建一个虚拟环境,并在其中安装依赖。使用同一个 Python 解释器运行 Chromium 安装命令,以保持浏览器依赖与 Playwright 对齐。
python3 -m venv .venv
.venv/bin/python -m pip install "haystack-ai==3.4.0" "capsolver-core[playwright]==0.1.1" "playwright==1.64.0"
.venv/bin/python -m playwright install chromium
以上命令使用的是类 POSIX 的环境路径。如果你的操作系统使用不同的虚拟环境结构,请使用对应环境中的 Python 可执行文件。Playwright Python 安装指南中包含了浏览器安装的要求。
该工具封装了来自官方 Core SDK 的 get_captcha_info(page)。页面对象由函数捕获,因此工具本身不接收导航参数。它的 JSON 参数模式不接受任何输入字段。
将下面内容保存为 haystack_captcha_inspection.py。本地 HTML 响应由 Playwright 路由提供,它是一个开发用夹具,而非远程托管的应用。reCAPTCHA 脚本则从 Google 加载。程序无需点击控件或提交表单即可读取参数。
import asyncio
import json
from capsolver_core import create_capsolver
from haystack.tools import Tool
from playwright.async_api import async_playwright
TEST_PAGE = """<!doctype html><html><body>
<div id="captcha" class="g-recaptcha"
data-sitekey="6LeIxAcTAAAAAJcZVRqyHh71UMIEGNQ_MXjiZKhI"></div>
<script src="https://www.google.com/recaptcha/api.js" async defer></script>
</body></html>"""
async def main():
async with async_playwright() as pw:
browser = await pw.chromium.launch()
try:
page = await browser.new_page()
await page.route("http://127.0.0.1:8765/", lambda route: route.fulfill(
status=200, content_type="text/html", body=TEST_PAGE))
await page.goto("http://127.0.0.1:8765/")
await page.wait_for_function(
"() => window.___grecaptcha_cfg && "
"Object.keys(window.___grecaptcha_cfg.clients || {}).length > 0")
async with create_capsolver() as cap:
async def inspect_captcha():
infos = await cap.get_captcha_info(page)
return {"captchas": [
{"type": info.type.value,
"website_url": info.website_url,
"website_key": info.website_key}
for info in infos
]}
captcha_tool = Tool(
name="inspect_current_page_captcha",
description="Read CAPTCHA types and public parameters from the current approved page; does not solve or submit.",
parameters={"type": "object", "properties": {},
"additionalProperties": False},
async_function=inspect_captcha,
)
result = await captcha_tool.invoke_async()
print(json.dumps(result, indent=2))
finally:
await browser.close()
if __name__ == "__main__":
asyncio.run(main())
async_function 参数非常关键,因为 SDK 和 Playwright 操作都是异步的。Haystack 的 Tool API 参考文档中说明了这种场景下应使用 invoke_async()。如果把一个协程放进仅支持同步调用的路径,很可能在任何 CAPTCHA 检查开始之前就失败。
上下文管理器和 finally 代码块会关闭 SDK 和浏览器资源。将该清理逻辑保留在你改造为长生命周期应用的版本中;否则页面加载失败时可能会留下浏览器进程。
领取你的 CapSolver 奖励码
立即提升你的自动化预算!
在为 CapSolver 账户充值时使用奖励码 CAP26,每次充值都可额外获得 5% 奖励 —— 无次数上限。
现在就在你的 CapSolver 控制台 中兑换
运行脚本会直接调用 Haystack 工具,并打印其返回的字典。在示例中,该字典包含一个带有单个 reCAPTCHA v2 条目的 captchas 列表。
.venv/bin/python haystack_captcha_inspection.py
本地运行返回 type 为 reCaptchaV2,website_url 为 http://127.0.0.1:8765/,website_key 为 HTML 中配置的公共测试站点密钥。这些字段都是通过真实 SDK 和浏览器读取的,而不是在工具中模拟填入。
结果刻意保持精简。完整的 SDK 描述符可以包含更多字段,但代理只应接收其下一步决策所需的信息。站点密钥是一个公共控件标识符;它不是 CapSolver 账户密钥,也不是站点的私有验证密钥。
本次运行证明:Haystack 能调用异步函数,浏览器可以加载开发用控件,Core SDK 能读取其参数。它不能证明:模型驱动的工具选择、所有站点上的生产 CAPTCHA 检测、令牌成功生成,或网站后台已接受验证。这些都需要在实际应用中分别检查。
当你在 Haystack Agent 中添加该能力时,应保持 Tool 对象和页面绑定不变。Haystack 的 Agent 通过文档化的 tools 配置接受工具。将该对象与应用已有的工具一起注册,同时在调用期间保持浏览器页面存活。
在现有浏览器工作流中,将本地夹具的搭建代码替换为应用已经打开并被授权检查的页面。保持浏览器导航逻辑在该工具之外。这样可以使页面选择变得明确,并防止模型生成的 URL 静默改变检测目标。
准确命名并描述该工具。示例中的描述明确指出:它读取 CAPTCHA 信息,不执行求解或提交。若描述成“完成验证”之类,就会夸大函数本身的能力,并可能诱导代理过早报告成功。
一个合理的应用决策是:如果结果中包含具备所需参数的已识别控件,则提供合适的下一步;如果结果为空或不完整,则收集更多证据或请求人工审核。不要添加无条件循环,不断检查同一个不完整页面。
检测结果是求解决策的输入,而不是 CAPTCHA 解答本身。Core SDK 文档中有 solve(info)(用于令牌求解)和 solve_on_page(page)(更广义的浏览器工作流)。它们和 get_captcha_info(page) 的作用不同,并且需要单独的配置和授权。
在本指南中,请保持检测工具在目的上是只读的。如果你之后添加求解工具,应让应用验证检测到的类型和当前页面,在模型不可见的参数之外提供账户凭证,并按工作流需求配置预算和审批规则。返回一个清晰的结果,区分“获得了令牌”和“应用动作已完成”。
返回的令牌仍需要由相关应用进行处理。站点自身的验证逻辑和表单结果会决定预期操作是否真的成功。非空的 captchas 列表或一次成功的 Haystack 工具调用,都不能视为“应用已接受 CAPTCHA 响应”的证据。
排查问题时,应先判断是哪个层面失败:包安装、浏览器启动、控件加载、SDK 检测,还是工具调用。针对报错所指向的层面进行修改,而不是一次性替换多层组件。
使用当前激活的虚拟环境,通过 Playwright 命令安装 Chromium。一次成功的 pip install 只能证明 Python 包已安装,并不能保证匹配的浏览器二进制文件已经就绪。
检查浏览器是否加载了 Google 脚本,以及测试页面是否创建了控件。示例中的等待条件是“控件客户端已初始化”。网络失败可能发生在 SDK 能检测任何内容之前;此时反复重试求解并不能解决问题。
空结果意味着在该页面该时刻,这次检测没有发现任何受支持的描述符。这并不能证明页面不存在任何验证机制。请检查页面加载时机、传入的 page 对象,以及实际的控件。你还可以参考 CAPTCHA 参数检测指南,用另一种方式检查浏览器状态。
检查是否注册了同一个 Tool 对象,代理使用的模型是否支持预期的工具调用流程,以及浏览器会话是否仍然打开。把已成功的“直接调用”保留为一个独立检查点,这样模型配置问题就不会被误报成 CAPTCHA API 故障。
一个小型的 CAPTCHA 检测工具,可以在求解之前为 Haystack 应用提供一个清晰的检查点。从经过测试的开发页面开始,保留异步调用与资源清理,再把工具挂载到你现有工作流所控制的页面上。只有在每个新增操作都具备清晰的输入、经过验证的行为以及可观察到的结果时,才逐步扩展其职责。
在你被授权运行的工作流中,把 CapSolver 用于受支持的 CAPTCHA 步骤。将浏览器、求解结果和应用最终结果视作三个独立检查点,避免一次成功的工具调用掩盖某个失败的任务。
问:这个集成需要 MCP 吗?
不需要。示例在同一个应用中使用原生 Haystack Tool 与 Python Core SDK。它不会启动 MCP 服务器。
问:运行脚本需要 LLM 的 API 密钥吗?
不需要。脚本是直接调用 Tool 的。只有在你为该工具添加基于 LLM 的代理时,模型提供方的凭据才会变得相关。
问:示例是否会求解测试 CAPTCHA?
不会。它会加载控件并读取公共参数,既不请求求解令牌,也不提交表单。
问:同样的方法能否检查已有的 Playwright 页面?
可以。将工具绑定到已有的、已获授权的页面,并在调用期间保持该页面存活。可支持的描述符字段取决于 SDK 能在该页面上检测到什么。
问:为什么要使用没有参数的工具?
该函数已经知道当前已批准的页面。空的输入模式可以让导航和页面选择保持在应用程序的控制之下。
问:空结果是否意味着该页面可以作为普通内容安全处理?
不是。在继续之前请检查页面状态。空的检测结果也可能是由于时机问题、不受支持的机制,或小部件尚未完全初始化所导致的。

Anh Tuan
Data Science Expert
Turning task outcomes into actionable insights.
关于作者