Katana 评测:`-jc` 和 `-headless` 命中的是不同端点,没有单条命令能把两者都覆盖

最后更新于 August 17, 2026
Katana 评测:`-jc` 和 `-headless` 命中的是不同端点,没有单条命令能把两者都覆盖
AI 摘要
Katana 是 ProjectDiscovery 推出的端点发现爬虫——一个采用 Go 编写、MIT 许可的二进制工具,输入目标后会输出 URL 和端点,供流水线中的下一个工具继续处理。它既可以在不启用浏览器的 HTTP 模式下抓取,也可以使用 -headless 驱动 Chromium。官方建议通常把 headless 描述为覆盖更高的选项;而这个测试样例说明,端点的类型和数量同样重要。我搭建了一个小型网站,刻意放入三类彼此不同的端点,并在 v1.6.1 的 -d 4 条件下测试每种模式分别能发现哪些端点。

Katana 是 ProjectDiscovery 推出的端点发现爬虫——一个采用 Go 编写、MIT 许可的二进制工具,输入目标后会输出 URL 和端点,供流水线中的下一个工具继续处理。它可以在不启用浏览器的 HTTP 模式下抓取,也可以使用 -headless 驱动 Chromium。官方建议通常把 headless 描述为覆盖更高的选项;而这个测试样例说明,端点的类型和数量同样重要。

我搭建了一个小型网站,刻意放入三类彼此不同的端点,并在 v1.6.1 的 -d 4 条件下测试每种模式分别能发现哪些端点。普通 HTML 在所有四种配置下都能完整拿到 4/4 的链接,以及三跳深度链路。差异出现在通过 JavaScript 源码暴露的端点,以及运行时 DOM 变化生成的端点上。

在这个样例中,headless 找到了浏览器模式遗漏的运行时 DOM 类端点;而带 -jc 的标准模式找到了两个 headless 运行都没命中的 JavaScript 文件字面量端点。四种命令组合里,没有任何一条能同时覆盖这两类端点。作用域、断点续跑和 known-files 行为则构成了其他几个实际边界。

Katana 到底是什么

Katana 爬虫——GitHub 上的 projectdiscovery/katana——使用 Go 编写,并采用 MIT 许可。我在 2026 年 7 月 27 日测试的是 v1.6.1;版本之所以重要,是因为下面关于覆盖率和 known-files 的结论,都是基于具体构建版本得出的观察结果。

这里最关键的是分类本身。端点发现爬虫 不是字段提取器。如果你想要一个 Go 网页爬虫,能把商品名和价格整理成结构化 JSON,那 Katana 压根不是那个方向——它只会告诉你 /products/1138 这个路径存在,却不会告诉你页面里有什么。这是设计使然;拿它和抽取能力做比较,就像评估金属探测器能否鉴定珠宝一样。

它真正擅长的是红队侦察和自动化流水线:从 STDIN 进,往外吐 URL,再接到下一个工具。也因此有个必须先说清的前提——这里所有测量都基于我自己写的、跑在 127.0.0.1 上的本地样例。请只在你拥有或已获得书面授权的主机上使用 Katana,别用在其他地方。本文讨论的不是如何绕过防御,而是某条命令到底能枚举出多少站点端点面。

三种模式,各自能看到什么

标准模式本质上就是一个 Go HTTP 客户端。它负责请求、解析 HTML、跟随 href 链接,但不会启动浏览器。速度快、成本低,但对任何只有在 JavaScript 运行后才出现的内容都看不见。

-jc-js-crawl)是在这个无浏览器路径上再挂一层 JavaScript 解析器。它会下载关联的 .js 文件,并从源码里提取看起来像 URL 的字符串字面量。这里不会执行脚本,只是读取源码。还有一个 -jsl(jsluice),README 里把它描述成更重、也更吃内存的解析器——我没有测试它,因此无法判断它是否会改变覆盖结果。

System diagram: Scope Is Applied in Layers

-headless 则会驱动 Chromium 并执行页面脚本。在这个样例里,它是唯一能恢复出“由片段拼接、并插入运行时 DOM”的路径的 Katana 模式。这个结果并不代表所有解析器或未来的 Katana 模式都能复现同样的能力。

接下来是作用域模型——这部分我建议你在真机生产环境里敲下任何命令前先记住。

标志控制内容取值 / 默认值
-fs(field scope)哪些主机参与抓取dnrdnfqdn,或自定义正则表达式——默认是 rdn
-cs-cos在该字段作用域内进一步过滤 URL 的正则
-kf已知文件:robots.txt 和 sitemap.xmlREADME 说明最少需要深度 3
-d深度默认 3
-resume继续一个中断的爬取任务

这个顺序并不是装饰性的:它决定了一个主机正则到底是在扩大爬取范围,还是悄无声息地把结果清空。

环境搭建:一个二进制,一个例外

三种安装方式,只有一种需要工具链:

安装方式前置条件
从源码安装:go install github.com/projectdiscovery/katana/cmd/katana@latest官方要求 Go 1.25 或更新版本
发布页上的预编译二进制不需要工具链
Docker 镜像不需要工具链

我这边安装后落在 ~/go/bin/katana,每次运行都显示 Current version: v1.6.1。到这里为止,还是熟悉的 Go 体验:单文件、无需运行时。

例外在 headless 这边,浏览器是独立于二进制之外的前置条件:

-headless 的运行位置所需条件
我的机器Katana 自动识别到了已安装的 Chromium;我没有记录浏览器构建版本,也没有手动提供浏览器路径
一台空白服务器,按项目自己的 Ubuntu 安装说明需要先执行 apt install google-chrome-stable,headless 才能工作
Docker 路线使用 -system-chrome 以 headless 方式运行

在空白服务器上,这种便利性就不存在了。只要命令行里出现 -headless,你就得同时准备浏览器,而不只是一个二进制文件。

如果你在 CI 里跑,还有个更小但值得注意的点:Katana 启动时会向 GitHub 发起版本检查请求。-duc 可以关闭它。放在笔记本上这点请求基本只是噪音;但在离线或限流的 runner 上,它就是每次运行都会多出的一个你并不想要的网络往返。我在计时测试里都加了 -duc,这样统计到的才是爬取本身,而不是“回拨”开销。

我是怎么测的

我专门设计了三类端点,因为它们能把不同模式区分开。所有内容都放在一个 本地样例服务器 上,而且在任何爬取开始之前就已经把“标准答案”记录下来,所以召回率是相对于固定集合来算的,而不是相对于 Katana 恰好打印了什么。

  • A 类——普通 HTML。 /page/a/page/b/page/c,以及一个三跳链路 /depth/1 → /depth/2 → /depth/3。任何爬虫都应该能抓到这些。
  • B 类——JavaScript 文件字面量。 /api/js-endpoint-7/api/js-endpoint-8 只以字符串字面量的形式存在于关联的 /static/app.js 中。如果有工具愿意读 JS,不执行也能看到。
  • C 类——仅运行时 DOM。 一个路径由片段运行时拼出来('endpoint' + (6 * 7)),并由脚本注入 DOM。字符串 /runtime-only/endpoint42 在服务器发送的任何字节里都不会连续出现——HTML 里没有,JS 源码里也没有。只有执行之后才会显现。

除此之外,还有 robots.txt、带着两个 <loc> 端点的 sitemap.xml、一个返回 500 的路由、一个失效链接,以及一个指向不同 hostname、且超出作用域的链接。

测试仪器和样例本身同样重要:服务器统计的是真实被请求过的内容,所以作用域和 resume 的结论都以实际命中为准,而不是以 Katana 自己 stdout 的输出为准。如果你想检查我的计算过程,原始运行结果已经提交到了 benchmark 仓库

那个没人量化过的覆盖率分裂

Measured results chart: Endpoint coverage by Katana mode

-d 4 下,按端点类别和模式整理后的矩阵如下:

模式HTML 链接 (A)深度链路 (A)JS 文件字面量 (B)运行时 DOM (C)
standard4/43/30/2未发现
standard -jc4/43/32/2未发现
-headless4/43/30/2找到
-headless -jc4/43/30/2找到

把最后两列放在一起看,问题就一目了然了。B 类只被一个配置发现:带 -jc 的标准模式。C 类只被两个配置发现:两个 headless 运行都命中了。不存在任何一行能同时覆盖这两列。完整矩阵见 discovery-summary.json,其中计算字段 headless_jc_covers_both 的值为 false

实际意义是,“直接用 headless,覆盖率更好”这句话对于这个测试来说是不完整的。headless 并没有在标准模式结果的基础上再补上 B 类;它只是找回了 C 类,同时漏掉了 B 类。要在这个样例里覆盖所有植入的端点类,必须跑两次再合并:

katana -u https://target.example -jc -d 4 -silent -o pass-jc.txt
katana -u https://target.example -headless -d 4 -silent -o pass-headless.txt
sort -u pass-jc.txt pass-headless.txt > endpoints.txt

我最希望上游给出解释的,是 -headless -jc 这一行。把 JavaScript 解析器加到 headless 运行里,并没有带来任何额外收益——B 类依旧是 0/2,每一次 headless 测试都是如此,包括重新复现的一次。我这里只是在报告现象,不是在声称我已经追到了内部机制;我没有去插桩 Katana 内部代码,因此也不知道为什么浏览器路径在这里不再贡献 JS 文件字面量。把它当成一个可复现的观察和一个值得提 GitHub issue 的点,而不是诊断结论。(顺带一提:在 v1.6.1 的 macOS ARM 上,-hl -jc 组合能干净结束并返回 0,这在历史上并不总是如此。)

官方文档 把 headless 描述为能带来更好的覆盖率,这在这里对“运行时渲染”类端点确实成立。但文档并没有明确说明这种“源码字面量 / 运行时 DOM”的分裂,所以应把这个矩阵当作一个提醒:你的端点类别要分别测试两条路径,而不是把它当作通用分类法。

headless 的时间成本有多高

在一台相对空闲的机器上,每种模式连续跑三次:

模式p50最小–最大均值
standard13.08s13.07–13.17s13.11s
-headless66.82s66.78–67.68s67.09s

这个比例是 5.1 倍,而且范围完全不重叠——我最慢的 standard 运行(13.17 秒)仍然比我最快的 headless 运行(66.78 秒)快了 53 秒以上(见 cost-summary.json)。这不是测量噪声。

对这 13 秒做一个说明:我的样例故意包含了一个返回 500 的路由和一个失效链接,而标准模式在这两处都会停留在默认的 -timeout 10 重试尾部。我没有通过调低超时来“美化”标准模式的速度,因此,若是调整过的标准运行,差距大概率只会更大,而不是更小。

这个比例反映的是本地容量信号,不是生产环境的预测值。真实目标在延迟、失败、脚本执行量和调度上都可能不同,而这个样例又带有默认超时尾部。你可以把这里测出的 5.1 倍差异,当作判断 headless 是否需要单独预算、单独目标子集的依据;然后再在具有代表性的、已授权的主机上验证你的方案。

作用域守住了,但有个标志其实没起作用

作用域测试用了两台服务器:主服务器在 127.0.0.1 上,另一台则在不同端口上以 localhost 可达,并提供了一个只存在于那边的路径。所以,只要命中了那个路径,就能证明越界主机真的被请求过,而不是只是被打印出来。

配置是否请求到越界主机?第二台服务器上的命中次数
默认(-fs rdn0
-fs fqdn0
-cs localhost0
`-fs '(127.0.0.1localhost)'`

作用域纪律是个好消息:默认情况下 Katana 会老老实实待在本地,要扩大范围必须显式操作。对于一个会被指向别人基础设施的工具来说,这才是正确的默认行为。

最值得注意的是 -cs localhost 这一行。它并没有把爬取范围扩大到第二台主机——而且它还完全没有输出任何 URL。因为 -cs 是在字段作用域内部做过滤,而字段作用域仍然停留在主机一侧的原始范围内,所以这个正则根本匹配不到任何东西,最终返回的是空集而不是报错。如果你曾经写过一个爬取范围正则,明明想把某台主机纳入范围,却盯着一个空输出文件发呆,这就是背后的机制(见 scope-summary.json)。要添加主机,请设置 -fs;要在已有主机内部进一步收窄,再用 -cs / -cos

resume 的粒度比标志名暗示的更粗

README 把这个标志写作 -resume string resume scan using resume.cfg,看起来像是在工作目录里丢一个文件。但事实并不是这样。我这边实际测到的检查点文件写在 ~/.config/katana/resume-<xid>.cfg,这是测出来的,不是从文档里读出来的,因为文档并没有写明路径。

更关键的是文件内部的内容。这个文件里只有一个 InFlightUrls 映射,而且映射中只包含一件事:种子 URL。没有已访问集合,也没有前沿队列。所以当我在 3 秒后用 SIGINT 中断爬取,再恢复时,实际发生的是下面这个结果:

运行不同路径数
完整基线爬取11
中断前已抓取10
恢复运行重新抓取全部 11 个,包括已经完成的那 10 个

resume 最终还是拿到了同样的端点集合,所以功能并没有坏。但检查点的粒度是按输入种子,不是按单个 URL——内存里的去重过滤器并不会被持久化,因此单种子任务恢复时,会把这个种子从头再爬一遍(见 resume-summary.json)。如果你给 Katana 喂的是 500 个主机地址,那么 resume 理论上应该能帮你省掉那些已经完整跑完的主机;这种多种子行为从状态存储方式上看得出来,但我这里只测了单种子场景。如果你是在一个特别大的站点里深挖,resume 带来的主要是正确性,而不是时间收益。

known files:请求了,但随后就没了下文

System diagram: Known files: requested, then dropped

-kf all -d 3 确实请求了这两个文件——robots.txt 和 sitemap.xml 都出现在服务器命中日志里——但随后却从该 sitemap 的 <loc> 元素中恢复出了 0/2 的端点。召回率为 0.0。

在把它直接判定为限制之前,我先尝试把责任归到自己身上。结果不管怎么变体,结论都一样:

尝试的变体恢复出的 sitemap <loc> 端点
-kf all0/2,召回率 0.0
-kf sitemapxml0/2,召回率 0.0
-kf robotstxt0/2,召回率 0.0
深度 30/2,召回率 0.0
深度 40/2,召回率 0.0
深度 50/2,召回率 0.0
额外加上 -jc0/2,召回率 0.0
直接从 /sitemap.xml 作为种子0/2,召回率 0.0

文档里要求的条件——使用 -kf,并且至少爬到 3 层深——我每次都满足了。所以这不是“少了哪个标志”的问题。

更实用的结论先给出:在这个使用 IP 字面量的样例里,千万不要想当然地认为“请求到了 known files”就等于其中的 <loc> URL 也会自动并入爬取。要么自己验证召回率,要么把这些 URL 提取出来后再手动作为种子喂给 Katana。

v1.6.1 的代码路径与这个观察结果是一致的,但我在运行时没有对它做插桩。在 v1.6.1 的 sitemapxml.go 中,NewNavigationRequestURLFromResponse 会根据响应构造 <loc> 导航请求,但不会带上已填充的 RootHostname。随后请求会进入 ValidateScope;而在 v1.6.1 的 scope.go 中,IP 字面量分支会把 URL 主机和那个空的 root 做比较,从而可能拒绝该 URL。自定义的 -fs '(127.0.0.1|localhost)' 命令在另一个作用域测试里走了不同的分支,所以它是源码推导出的补救方案,而不是我实际测过的 -kf 解决办法。由于这个主机上的 known-files 客户端偶发拨号不稳定,验证尝试被拦住了,因此报告结果仍然是 0/2。

如果今天真要上生产,在有人正式确认这个标志之前,我会直接自己抓 sitemap,提取 <loc> 里的 URL,然后把它们作为种子列表交给 Katana。两行 shell 就够了,而且完全不涉及作用域校验。

还有一件事表现得完全符合预期,也值得单独说一句:那个返回 500 的路由和失效链接都被成功请求、记录并跳过了。所有 browserless 运行最终都返回了 0。一个遇到第一个坏响应就死掉的爬虫,根本不适合无人值守;而 Katana 没有这个问题。

部署前先做一个针对目标的覆盖检查

这个样例矩阵最有价值的地方,是它可以直接当成测试你自己已授权目标的模板。运行 Katana 之前,先定义好端点类别:普通链接、关联脚本里的字面量、只能在执行后出现的路由、以及 known-files 条目,这四类都是不错的起点。每一类都保留一小份真实答案样本。如果没有这份事先列表,stdout 里哪怕结果更多,也可能只是看起来覆盖更高,实际上某一类已经消失了。

首先把 browserless 和 headless 路径当成两次独立测量来跑。保存精确命令、Katana 版本、浏览器构建版本、返回码和输出。对端点集合做标准化后再 diff,不要只比行数。如果样本里标准 -jc 没带来任何独特结果,那只用 headless 的策略可能就够;如果像这里一样两边结果分化,那就保留两次运行,收集完再合并。不要想当然地认为,一个命令里同时加上两个标志,就一定等于两条路径结果的并集——这件事必须由目标本身的差异来验证。

验证作用域时,要拿 Katana 输出之外的证据来交叉确认。放一个应当被排除的 host 上的 canary URL,然后检查那台服务器的请求日志。如果爬取范围本来就应该扩展,也要测试预期中的第二台主机。这里的 -cs localhost 之所以输出为空,是因为内容作用域过滤并没有扩大字段作用域;而自定义的 -fs '(127.0.0.1|localhost)' 调用确实联系到了第二台服务器。记录完整的正则表达式很重要,因为只改一个字符,改变的可能不是展示方式,而是正则本身。

对于中断恢复和 known files,要把测试与发现召回率分开验证。resume 方面,可以在代表性种子上运行几页后中断,保存生成的检查点路径,再统计有多少已完成 URL 被重新请求。-kf 方面,要同时确认 robots/sitemap 确实被请求到了,以及 sitemap 里的 <loc> URL 是否真的被排进了任务队列。这两个结论并不相同。在这个样例里,文件被请求到了,但那两个 sitemap 端点并没有出现,所以必须同时看请求日志和端点输出,才能看清边界。

最后,在一台相对空闲的机器上用连续运行建立本地成本基线,然后再在具有代表性的主机上重复测试。保留最小值、最大值和中位数,不要只保留一个倍数。这里的 5.1 倍已经包含了样例中的失败和超时行为;它告诉你 headless 值不值得单独预算,而不是告诉你生产环境盘点要花多久。

优点与缺点

优点:

  • 在所有模式下,对普通 HTML 的召回都很完整——4/4 链接和完整的 3/3 深度链路,无需额外配置。
  • -jc 在无浏览器模式下确实有效:能从关联 JS 文件里的字符串字面量恢复 2/2 个端点,而且不需要浏览器成本。
  • 只有 -headless 找到了运行时拼接出的端点——这类内容按设计就是源码解析看不到的。
  • 作用域默认值比较保守。默认、-fs fqdn-cs 下,越界主机都不会被请求。
  • 单个 Go 二进制、MIT 许可、预编译构建、Docker 镜像,输入输出也很适合流水线。
  • 面对失败比较稳:500 和失效链接不会直接把爬虫打停。

缺点:

  • 没有任何一次调用能同时覆盖 JS 文件端点和运行时 DOM 端点。要完整覆盖,必须跑两次并合并结果。
  • -headless 下,-jc 没带来任何额外收益——B 类在每次 headless 运行里都保持 0/2。
  • headless 的 wall time 要贵 5.1 倍(p50 为 66.82 秒 vs 13.08 秒,区间完全不重叠)。
  • -resume 会重新爬已经完成的页面。它恢复的是端点集合,不是你已经花掉的时间。
  • known-files 请求了 robots.txt 和 sitemap.xml,但针对 IP 目标时,从 sitemap <loc> 中恢复出的端点是 0/2。
  • headless 在机器上还得有 Chromium;“一个二进制”这个说法,到浏览器这里就不成立了。
  • 它只做发现,不做结构化抽取,不做内容转换,也不定义字段 schema。

以下内容没有测试,因此也不在这些数字的覆盖范围内:-jsluice、在 -d 1 / -d 2 下的专门深度截断测试、多种子 resume、自动表单填充,以及任何真实的、脚本密集或受保护的生产站点。这里所有数据都只来自一台机器(macOS arm64)和一个本地样例。

适合谁,不适合谁

如果你的工作是为你有权限接触的基础设施输出端点清单,Katana 的流水线形态其实很对:STDIN/STDOUT 管道、可分发二进制、以及无浏览器 / 有浏览器两种模式。这个样例里,双路合并是覆盖植入类端点的必要步骤;你的目标是否也需要两次运行,需要你用代表性页面自己验证。

如果你想要的是数据而不是地址,就跳过它。Katana 永远不会给你一个商品表;它给你的只是商品可能所在的 URL,而真正的抽取交给别的工具。若你还要求“一条命令就必须完整”,也可以跳过——两次运行后再合并,在流水线里没问题,但在交互式命令行里就显得麻烦。还有,如果你的枚举依赖 sitemap <loc> 端点,而目标又是 IP,先确认你实际拿到的是什么,再决定是否相信输出;因为在我的样例里,这条路最后什么都没有返回。

替代方案,以及抽取边界

Katana 是免费、MIT 许可、可自托管的。发现、模式选择、浏览器部署和结果合并,这些都留在你自己这边完成。

在开源工具里,更有意义的比较方式是按任务而不是按语言来分。 Colly 是另一个 Go 方案,但它本质上是个库,需要你自己编写回调,而且根本不渲染 JavaScript。 Crawl4AI 会运行真实浏览器,并为 LLM 流水线输出 Markdown,产物完全不同。如果你同时在比较这几种工具,我们的 开源爬虫总览 把各类工具并排列得很清楚。

披露: Thunderbit 是发布方自有产品,在这次 Katana 样例中没有被测试。它位于受管抽取这一后续环节,把页面转换为文本或结构化记录,而不是枚举已授权目标的端点面。一个工作流里可以同时用到这两类工具,但这篇评测只提供了 Katana 发现行为的证据。

试用 Thunderbit 进行网页数据提取

结论

如果你的交付物是一个端点列表,并且目标是你有权限抓取的站点,同时你还能针对这些目标验证不同模式的覆盖情况,那么就该用 Katana。在这个样例中,标准 -jc 找到了植入的 JavaScript 文件字面量,而 headless 找到了运行时 DOM 端点;Katana 测试过的无浏览器模式没有恢复出那个运行时路径。默认作用域还会保持第二台主机不被请求,而浏览器less 运行也能稳稳跨过 500 和失效链接。

但需要注意的操作性限制也很明确:混合端点类型时可能需要两次运行合并;headless 的本地耗时约为标准模式的五倍;单种子 resume 会把已完成路径重新抓一遍;known-files 针对 IP 目标的召回是 0/2。这些都是 v1.6.1 在本地样例上的结果,不代表每个站点都如此;但它们足以定义生产评估时该重复检查的项目。

试用 Thunderbit 进行网页数据提取 Get Started Free

常见问题

Katana 的 resume 文件存在哪里?恢复后会跳过我已经爬过的页面吗? 检查点文件实际落在 ~/.config/katana/resume-<xid>.cfg,而不是标志帮助文字暗示的工作目录下 resume.cfg。而且它不会跳过已完成页面:这个文件只保存了正在进行中的种子 URL,所以单种子任务恢复后,会把 11 条基线路径全部重新抓一遍,其中包括那 10 条已经完成的。最终端点集合是一样的,只是时间不会省下来。

为什么 -kf all 请求了我的 sitemap.xml,却没有继续抓里面的 URL? 如果目标是 IP,这更像是作用域校验边界,而不是某个标志写错了。Katana 的 sitemap 解析器在构造每个 <loc> 请求时,没有把 root hostname 一并带上;接着 IP 字面量主机的 DNS 作用域检查会拿 URL 主机去和那个空的 root 比较,比较失败后把 URL 丢掉。我试过的每一种标志、深度和种子变化里,召回率都维持在 0。自定义的 -fs 主机正则会走另一条校验分支,从源码推断看它能解决这个问题——但我在本机上没法用 -kf 把它验证出来,所以只能把它当作未测试结论。今天最稳妥的做法,仍然是你自己提取 <loc> URL,再把它们作为种子喂给 Katana。

报告 Katana 覆盖率测试时,我应该保留哪些信息? 记录精确的 Katana 版本和命令,包括逐字节一致的 -fs 表达式;在运行前先定义好端点类别;保留服务端命中日志,而不只是 stdout;并把基于源码的推测和实测行为分开。对于 headless 运行,还要记录浏览器构建版本——这次测试没有记录,会限制复现能力。

我该用 -jc-headless,还是两个都用? 按你需要的端点类型来选。在这个样例里,标准 -jc 找到了存放在 JavaScript 文件中的字面量,而 headless 找到了插入到运行时 DOM 的端点。单独任一模式都不能覆盖两类端点,所以对混合目标来说,先跑两次再去重合并才是最稳妥的做法。

一个失败的 URL 会把整个爬取打断吗? 在这次受控运行里不会。Katana 在遇到 500 响应和失效链接后都继续往下跑了,最终仍然返回了其他可达路径。这不能替代生产环境里的错误统计:你还是要保留失败请求日志,并定义可接受的失败率,避免把“部分成功”误当成“完整覆盖”。

Ke
Ke
Thunderbit 首席技术官 | 高级数据科学家与机器学习专家 Ke Shen 拥有近十年的机器学习和数据科学经验,毕业于哥伦比亚大学,曾任 Walmart Labs 高级数据科学家。他在 Python、R、Java 和统计学方面拥有深厚且备受同行认可的专业能力,并分享如何将复杂的 AI 算法从理论落地到生产级架构的实战经验。
目录
Thunderbit · AI 网页数据代理

一键 内提取任意页面数据

深受 250,000+ 用户信赖
提供免费方案
从网页到表格
描述你的需求——Thunderbit 的 AI 代理会帮你抓取并导出到 Excel、Google Sheets、Airtable 或 Notion。可免费开始。
Chrome Store Rating
PRODUCT HUNT#1 Product of the Week