2026年8月3日 1 分钟阅读

网页抓取要给 Agent 多少浏览器能力?用 Draco 在 Markdown、SPA 数据与 MCP 之间分层取舍

tinyash 0 条评论

把网页交给 Agent 处理,最常见的第一步是“抓 HTML,再转 Markdown”。这在静态文档页上很有效;但一碰到客户端渲染站点,下载到的往往只是一层空壳。另一端的做法是直接起 Playwright 或远程浏览器,兼容性上去了,却把浏览器启动、并发隔离、会话污染和资源消耗一并引入。

Draco 是一个本地运行的网页抓取器,定位为较轻量的 Firecrawl 替代方案。它把网页处理拆成不同强度的路径:普通页面走抓取与正文提取;需要 JavaScript 的页面才进入进程内 V8 isolate;如果目标是页面背后的数据接口,还可以输出发现到的端点。这个分层本身比“所有 URL 都开浏览器”更值得借鉴。

它的仓库提供 MIT 或 Apache-2.0 双许可证,安装脚本会按操作系统和架构下载二进制。对于已经有 Rust 工具链的环境,也可以自行编译。这里不把“更快”当成绝对结论:README 中约 300 ms 的描述针对普通 HTML 页面,真实耗时仍取决于目标站点、网络、代理和是否需要运行页面脚本。

先把最小路径跑通:URL 到 Markdown

安装后,最小用法就是将 URL 交给 scrape。默认结果写到标准输出,因此适合接进文件、全文索引或后续的 Agent 上下文处理。

curl -fsSL https://raw.githubusercontent.com/0xchasercat/draco/main/install.sh | sh

draco scrape https://example.com > page.md

Draco 的正文输出会保留标题、链接、列表、引用、围栏代码块和 GFM 表格,并尝试剔除导航、页脚、广告、脚本与样式。对需要追踪来源的流程,只拿 Markdown 不够;可以改用 JSON 包装结果,检查标题、规范链接、内容类型、HTTP 状态以及各处理步骤的耗时。

draco scrape https://example.com --json --pretty

这一层的适用边界很明确:它解决的是“将页面阅读材料规整为可消费文本”,不是绕过登录、付费墙或站点访问控制。即便工具提供了代理和 --ignore-robots 参数,也不应把它们当成忽略网站条款或 robots 规则的默认开关。把目标域名、频率和允许的抓取路径显式写进自己的策略,比事后补救更可靠。

SPA 不是天然要开浏览器:先判断内容在哪一层

现代站点的首屏 HTML 可能只有一个 root 容器,正文在 JavaScript 水合后才出现。Draco 的第二层会在进程内 V8 isolate 中运行页面脚本:先序列化水合后的 DOM,再复用正文提取管道生成 Markdown。可以用 --tier-max 1 限制到静态层,作为排错或成本控制手段。

draco scrape https://spa.example.com

draco scrape https://spa.example.com --tier-max 1

两次输出的差异很有价值。若静态层已经足够,就不必增加运行时执行;若第二次能得到正文,说明页面确实依赖客户端渲染。Draco 文档说明,Tier 2 中页面 JavaScript 没有网络、文件系统或进程等宿主能力;页面触发的请求由引擎代理,状态变更请求默认不做实时回放。这个设计降低了“为了读页面就无约束执行页面代码”的风险,但不等于目标页面和抓取结果天然可信:进入知识库前仍要校验来源、时间和引用链。

另一个实用场景是数据型 SPA。--format json 会按嵌入状态、Next.js 数据请求和运行时拦截等层次寻找数据;endpoints 则用于查看发现到的接口目录。对数据团队来说,先发现页面实际调用的公开数据接口,再决定是保存网页正文还是接入结构化数据,通常比从渲染后的 DOM 反复解析稳定。

draco scrape https://app.example.com --format json --pretty

draco scrape https://shop.example.com --format endpoints --pretty

这里的失败模式也要提前设计。某些接口依赖登录态、短期令牌或反爬策略;另一些接口即使能被观察到,也可能不适合被自动重放。把“发现端点”与“允许请求端点”分成两个审批步骤,避免让 Agent 从可见性直接跳到执行权限。

从一次性命令升级为本地服务,但不要误认成完整浏览器 API

需要被多个内部任务调用时,可以启动常驻服务。它使用 Firecrawl 兼容的 REST 路径,默认监听本地 3002 端口;文档明确指出目前仅支持 Markdown 和 JSON 格式,HTML、raw HTML、links、screenshot 等未实现格式会返回 400。因此迁移已有客户端前,应当先列出真正使用的字段,而不要只因“兼容”就假设全部接口行为相同。

draco serve

curl -X POST http://127.0.0.1:3002/v1/scrape \
  -H 'content-type: application/json' \
  -d '{"url":"https://spa.example.com","formats":["markdown"]}'

服务默认绑定 127.0.0.1 是一个合理起点。若为了局域网访问改为 0.0.0.0,应额外放在反向代理、访问控制或私有网络之后;抓取能力一旦暴露给不可信调用者,很容易被用于请求内网地址或消耗外部站点资源。并发也不是越高越好:Draco 提供 --max-concurrency,应根据出口带宽、目标域名限速和机器资源设置上限。

把 trace 当作质量门,而不是调试残留

网页抓取进入自动化后,最难排查的往往不是“命令报错”,而是“命令成功却得到不该信任的内容”:目标站临时返回登录页,正文被骨架屏替代,规范链接跳到另一个语言版本,或者页面改版后正文选择器悄悄失效。Draco 的 JSON 包装结果包含 tracetiming,这使调用方能把抓取过程变成可检查的输入,而不是只接收一段 Markdown 字符串。

建议把以下判断做在入库之前:第一,确认 statusCode 在业务允许范围内;第二,检查 sourceURL 与请求 URL 是否仍在允许域名内;第三,为每类页面定义最小正文长度或必须出现的标题词;第四,记录实际 sourceTier。例如,一个原本应静态可读的文档页突然只能经 Tier 2 才得到内容,未必是失败,却是站点实现变化的信号,应该进入监控而非静默吞掉。

draco scrape https://docs.example.com/guide --json --pretty > result.json

不要把正文长度作为唯一质量条件。登录页、错误页和营销页也可能很长;更稳妥的组合是 HTTP 状态、标题、canonical、预期关键短语和来源域名。对于被 Agent 再次引用的内容,还应保存抓取时间与原始 URL,以便回答“这段结论来自哪里、当时抓到了什么版本”。

如果抓取任务要进入队列系统,建议将失败分成三类:网络错误可以有限重试;unsupported 表示当前格式或目标能力不匹配,应转人工或其他工具;正文质量未通过则保留 trace 和短样本,等待规则调整。把三者都当成“再试一次”,会增加对目标站的无效访问,也掩盖真正的兼容性问题。

给编码 Agent 接 MCP 前,先缩小工具面

Draco 还提供 draco mcp,可作为 stdio MCP server 使用。README 列出的工具包括读取页面的 draco_scrape、发现接口的 draco_discover 和搜索工具;它们被标注为只读。一个最小配置如下:

{
  "mcpServers": {
    "draco": {
      "command": "draco",
      "args": ["mcp"]
    }
  }
}

实际接入时,建议先只开放抓取功能,并为 Agent 设置允许域名、超时、每轮调用次数和结果大小上限。接口发现比纯阅读更敏感,尤其是配合可能产生请求的工作流时,应当单独授权。这样做的目标不是限制 Agent “聪明”,而是让抓取链路的成本、网络边界和数据来源可复盘。

选择 Draco 的判断标准

如果你需要的是本地、可管控的“网页到 Markdown”入口,并且希望对 SPA 水合与数据接口发现有按需升级的路径,Draco 值得试验。它不适合被描述为全功能浏览器自动化平台:截图、完整 HTML 输出等能力在当前服务接口中并未提供;复杂登录、交互式流程也需要先验证是否落在其支持范围内。

最稳妥的落地方式是从单个公开文档域名开始:先保存 --json 的元数据和 trace,比较静态层与运行时层的结果,再把通过质量检查的 Markdown 送入检索或 Agent。把“抓到了内容”与“可以信任、可以自动处理”分开,才是网页能力进入 Agent 工作流后最重要的工程边界。

相关链接

发表评论

你的邮箱地址不会被公开,带 * 的为必填项。