CAPSOLVER
博客
如何将验证码检测工具添加到 Haystack 代理中

如何为 Haystack 代理添加 CAPTCHA 检测工具

Logo of CapSolver

Anh Tuan

How to use CapSolver

22-Oct-2026

摘要

  • Haystack 工具可以调用官方的 CapSolver Core SDK 来检查现有浏览器页面上的 CAPTCHA 参数。
  • 将工具绑定到你的应用程序已经控制的页面,而不是让代理通过检查工具随意访问任意 URL。
  • 示例程序会从一个本地页面(使用 Google 的 reCAPTCHA v2 测试控件)返回 CAPTCHA 类型、页面 URL 和公共站点密钥。
  • 这是一个原生 Python 集成:不需要 MCP 服务器或任何传输层。
  • 检测步骤不会创建求解任务、不会返回令牌,也不能证明应用已经通过验证。

当浏览器代理被 CAPTCHA 打断时,它需要有用的信息。仅有页面标题或截图,并不足以让代理知道当前是哪一类 CAPTCHA,或者下一步所需的参数是什么。返回一个小而结构化的结果,可以在应用请求求解之前,为其提供一个清晰的决策点。

Haystack 是一个用于构建 AI 应用、检索流水线和代理的 Python 框架。它的原生工具可以包装这些应用所用到的函数。本指南将 Haystack 工具与 CapSolver 连接起来,完成一个特定任务:检查当前浏览器页面并返回 CAPTCHA 参数。示例使用的是开发页面,不会发送任何付费求解请求。它为你提供了一个可用的“检测组件”,可以放在一个单独授权的求解步骤之前。

CAPTCHA 工具在 Haystack 工作流中的位置

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 对齐。

bash 复制代码
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 加载。程序无需点击控件或提交表单即可读取参数。

python 复制代码
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 控制台 中兑换
CapSolver CAP26 promotion offering a 5 percent recharge bonus

运行检测并理解结果

运行脚本会直接调用 Haystack 工具,并打印其返回的字典。在示例中,该字典包含一个带有单个 reCAPTCHA v2 条目的 captchas 列表。

bash 复制代码
.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 构建可靠的自动化工作流

在你被授权运行的工作流中,把 CapSolver 用于受支持的 CAPTCHA 步骤。将浏览器、求解结果和应用最终结果视作三个独立检查点,避免一次成功的工具调用掩盖某个失败的任务。

常见问题

问:这个集成需要 MCP 吗?

不需要。示例在同一个应用中使用原生 Haystack Tool 与 Python Core SDK。它不会启动 MCP 服务器。

问:运行脚本需要 LLM 的 API 密钥吗?

不需要。脚本是直接调用 Tool 的。只有在你为该工具添加基于 LLM 的代理时,模型提供方的凭据才会变得相关。

问:示例是否会求解测试 CAPTCHA?

不会。它会加载控件并读取公共参数,既不请求求解令牌,也不提交表单。

问:同样的方法能否检查已有的 Playwright 页面?

可以。将工具绑定到已有的、已获授权的页面,并在调用期间保持该页面存活。可支持的描述符字段取决于 SDK 能在该页面上检测到什么。
问:为什么要使用没有参数的工具?

该函数已经知道当前已批准的页面。空的输入模式可以让导航和页面选择保持在应用程序的控制之下。

问:空结果是否意味着该页面可以作为普通内容安全处理?

不是。在继续之前请检查页面状态。空的检测结果也可能是由于时机问题、不受支持的机制,或小部件尚未完全初始化所导致的。

合规声明: 本博客提供的信息仅供参考。CapSolver 致力于遵守所有适用的法律和法规。严禁以非法、欺诈或滥用活动使用 CapSolver 网络,任何此类行为将受到调查。我们的验证码解决方案在确保 100% 合规的同时,帮助解决公共数据爬取过程中的验证码难题。我们鼓励负责任地使用我们的服务。如需更多信息,请访问我们的服务条款和隐私政策。

更多