Apache Nutch 评测:决定它能否运行以及能发现什么的四道边界

最后更新于 August 14, 2026
Apache Nutch 评测:决定它能否运行以及能发现什么的四道边界
AI 摘要

Apache Nutch 是 Apache Software Foundation 旗下的爬虫项目,开发始于 2004 年。它是一个基于 Hadoop 的 JVM 系统,运作方式更像循环流程,而不是单条流式命令:先把种子 URL inject 到持久化数据库中,然后按 generate → fetch → parse → updatedb 的轮次运行,并通过插件槽位处理协议、解析器、URL 过滤和评分。它的常见输出目标是 Solr 或 Elasticsearch 这类搜索索引,而不是 CSV。我把 Nutch 1.22 跑在一个受控的本地测试站点上——这个站点会在服务器端记录每一次请求,因此结果以服务器实际看到的内容为准,而不是爬虫自己声称抓到了什么。

Keywords

apache nutch 评测, 网页抓取, 开源, 基准测试

Content

Apache Nutch 是 Apache Software Foundation 旗下的爬虫项目,开发始于 2004 年。它是一个基于 Hadoop 的 JVM 系统,运作方式更像循环流程,而不是单条流式命令:先把种子 URL inject 到持久化数据库中,然后按 generate → fetch → parse → updatedb 的轮次运行,并通过插件槽位处理协议、解析器、URL 过滤和评分。它的常见输出目标是 Solr 或 Elasticsearch 这类搜索索引,而不是 CSV。

我把 Nutch 1.22 跑在一个受控的本地测试站点上——这个站点会在服务器端记录每一次请求,因此结果以服务器实际看到的内容为准,而不是爬虫自己声称抓到了什么。整个运行过程由四道边界共同决定:JDK 版本、http.agent.name、爬取范围,以及 plugin.includes 里是否包含 parse-js。我用同一套测试配置反复跑完整流程;只要换掉 JDK,或者不设置 agent 身份,它就会在抓取到有用页面之前停住。

JDK 的边界在任何爬取开始前就会显现。Nutch 1.22 在 JDK 26.0.1 上根本起不来:第一个 Hadoop 作业就在 Subject.getSubject() 里挂掉了,因为 Java 已经移除了 SecurityManager 相关路径。Nutch 自带的是 Hadoop 3.4.2,而修复是在 Nutch 1.22 发布七天后才进入 Hadoop 3.4.3。另一方面,加入 parse-js 后,两个仅存在于 JavaScript 文件字面量中的地址恢复率从 0/2 提升到 2/2,而且不需要运行浏览器。

Nutch 的用途,以及它不擅长什么

Nutch 不是一个数据抓取器。它的职责不是做结构化字段抽取:它负责大规模发现和抓取 URL,维护这些 URL 及其状态的持久化数据库(crawldb),再把 segments 交给别的工具去生成索引。你如果拿它去抓商品目录、希望直接得到一个姓名和价格表,最后得到的只会是 crawldb。

这个架构也解释了后面的绝大多数现象。Nutch 比单体爬虫时代早了大约二十年,它是为 Hadoop 所解决的问题而生的:抓取超过单机承载能力的网页。把它放在笔记本上,对一个 12 页的测试样本跑起来,就像租一列货运火车去搬书架——这能很好地说明这列火车的能力,但拿自行车的使用感受去要求它就不公平了。

当前版本是 1.22,官方在 2026 年 2 月 17 日 发布。它采用 Apache-2.0 许可证;我在 2026 年 7 月 27 日查看时,仓库有 3,272 个 star,8 个 open issues,master 分支的最新提交还是四天前。这是一个仍在维护的项目,不是无人维护的遗产——从这个角度看 JDK 问题就更准确了:这是一个发布窗口卡早了一周的打包问题,而不是项目失修。

版本矩阵:JDK 24+、Hadoop 3.4.2,以及一处两行修复

真正的阻塞点来自三个版本之间的联动,而你能控制的只有 Nutch 运行在哪个 JDK 上。第一个 Hadoop 作业在宿主机默认 JDK 上就死在初始化阶段:

java.lang.UnsupportedOperationException: getSubject is not supported
    at java.base/javax.security.auth.Subject.getSubject(Subject.java:277)
    at org.apache.hadoop.security.UserGroupInformation.getCurrentUser(UserGroupInformation.java:588)
    at org.apache.nutch.crawl.Injector.inject(Injector.java:473)

返回码 255。没有抓到任何页面。bin/nutch inject 甚至还没碰到网络——它先初始化 Hadoop 的 LocalJobRunner,这个过程会询问当前用户是谁,进而调用 Subject.getSubject();而 JEP 486 在 JDK 24 永久移除 SecurityManager 后,把这一步变成了无条件异常。我的宿主机 JDK 是 OpenJDK 26.0.1,早已越过这条线。

传统的绕过办法也不行。添加 -Djava.security.manager=allow,这个过去能重新启用旧行为的参数,会在 Nutch 代码加载之前就被虚拟机拒绝:

Error occurred during initialization of VM
java.lang.Error: A command line option has attempted to allow or enable the Security
Manager. Enabling a Security Manager is not supported.

这是返回码 1,而且是设计好的死路——这个开关已经随着功能一起被移除了。

根因在 Nutch 1.22 自带的 Hadoop 版本里。getSubject 问题被记录为 HADOOP-19212,并已在 Hadoop 3.4.3 和 3.5.0 中修复;而 Nutch 1.22 打包的是 hadoop-common-3.4.2。Nutch 1.22 于 2026 年 2 月 17 日发布,而 Hadoop 3.4.3 大约在一周后跟进。

这也不是 Solr 或 Hadoop 集群依赖的问题。 很多人会默认 Nutch 必须接 Hadoop 集群、还得有一个运行中的 Solr 才能干活。事实并非如此。它的本地模式使用 Hadoop 内置的 LocalJobRunner——没有 HDFS 守护进程,没有 YARN,也不需要集群。完整的 inject → generate → fetch → parse → updatedb 流程可以在一台机器上跑完,甚至不用装别的东西。JDK 这道墙纯粹是随包依赖的版本问题,而且它在你考虑这些基础设施问题之前就把你拦下来了。

下面是实测得到的版本矩阵:

使用的 JDK命令结果
OpenJDK 26.0.1bin/nutch inject失败,rc=255 — UnsupportedOperationException: getSubject is not supported
OpenJDK 26.0.1bin/nutch inject + -Djava.security.manager=allow失败,rc=1 — 虚拟机拒绝启动
OpenJDK 17.0.20(LTS)bin/nutch inject成功,rc=0 — Total new urls injected: 1

修复办法只要两条命令。安装一个 LTS 版 JDK,并让 Nutch 指向它:

brew install openjdk@17
export NUTCH_JAVA_HOME=/opt/homebrew/opt/openjdk@17

这是 keg-only 安装,不会改动系统默认 JDK。Nutch 自己的 CI 也以 Java 17 为目标,而且项目已经 公开说明:1.22 是最后一个还能在 Java 11 上运行的版本,1.23 将要求 Java 17。因此,LTS JDK 不是临时补丁,而是受支持的配置。这里的错位在于:Nutch 支持什么,和 brew install openjdk 在 2026 年默认给你什么,是两回事,而这两件事恰好在第一条命令上撞在一起。

从这里开始,所有测试都运行在 OpenJDK 17.0.20 上,整个流程表现稳定。

真实安装成本:396 MB,以及一个会卡住一切的属性

“很重”是大家最爱用的形容词,但没有量化就没有意义。下面是解压后的 Nutch 1.22 二进制发行包里到底装了些什么:

项目Nutch 1.22 二进制发行包
解压后体积约 396 MB
lib/ 下的 jars188 个(约 113 MB)
——其中自带的 Hadoop 组件13
插件目录78
这些插件目录中的 jars533 个
配置文件35
bin/ 中的脚本2 个 —— crawlnutch

拿现代 Go 爬虫 katana 来对比,它通常只是一个大约 50 MB 的二进制文件,没有 JVM,也不需要外部 jars。

然后还有一个没人提醒你的关卡。随包提供的 nutch-site.xml 是空的,http.agent.name 默认也为空字符串。如果不设置它,我第一次爬取抓到了 0 个路径,日志里报了:

ERROR Fetcher: No agents listed in 'http.agent.name' property.

只要设置这一个属性,别的都不用动,抓取就恢复正常了。如果这个属性为空,命令会执行完,但不会抓到页面,而且日志里会明确出现上面的 agent-name 错误;它并不是静默失败。

最低可用配置实际上只需要三个文件:conf/nutch-site.xml(agent 名称、插件集合、scope)、conf/regex-urlfilter.txt(主机范围限制)以及一个种子 URL 文件。数量不算多,只是比 crawler run <url> 多了三个文件。

它找到了什么:真正起作用的插件开关

System diagram: What it found: the plugin toggle that matters

测试站点故意设置了三类不同的端点,Nutch 的表现也正好沿着这三类清晰分化:

  • A 类 —— 普通 HTML 链接(4 个页面,外加一个深度为 3 的链接链)
  • B 类 —— 只存在于某个已链接 JavaScript 文件中的字符串字面量端点:一个是函数调用参数,fetch('/api/js-endpoint-7'),另一个是赋值语句,const other = "/api/js-endpoint-8"
  • C 类 —— 只有在 JavaScript 运行后才会被注入 DOM 的端点

以下结果来自服务器端命中日志,且重复三次:

插件配置A 类(HTML 链接)B 类(JS 文件字面量)C 类(运行时 DOM)
随包默认 — parse-(html|tika)4/4(召回率 1.0)0/2(召回率 0.0)未触达
启用 parse-jsparse-(html|tika|js)4/4(召回率 1.0)2/2(召回率 1.0)未触达

三次重复结果完全一致,说明是确定性的。

B 类的提升最容易被低估。Nutch 在不运行浏览器的情况下就找到了这两个埋在 JavaScript 里的端点,靠的是 parse-js 插件对 JavaScript 内容的正则扫描。app.js 文件本身在两种配置下都会被抓取——因为 Nutch 会把 <script src> 当作外链处理——所以真正的差别只在于:有没有谁会去读取文件内容并寻找像 URL 的字符串。打开这个插件后,两种字面量形式都能被识别出来。

在这个测试样本上,Nutch 的默认模式和 katana 的标准模式都到达了同样的 A 类集合;而 Nutch 加 parse-js、以及 katana 加 -jc 时,都可以在不依赖浏览器的前提下达到 A 类和 B 类。本文没有记录 katana 的具体版本和完整命令,因此这一结论属于上下文对照,而不是严格的产品基准测试。

C 类是诚实的上限。任何静态插件配置都没能触达它,这也在预料之中:只在脚本执行后才出现的端点,必须真的执行脚本才能恢复。我确实尝试过把 protocol-http 换成 protocol-htmlunit,也就是 Nutch 自带的纯 Java、可执行 JS 的协议。它能加载并运行而不崩溃,但在同一个四轮测试框架里,它只完成了一轮,只抓到了种子页和 app.js,A/B/C 全都没有到达,而且第二轮日志显示 0 records selected for fetching。这说明的是配置不足,而不是 HtmlUnit 能力不足。它能证明的范围更窄:把一个可执行 JS 的协议直接替换进去,不是即插即用的改法,而且我测试的所有配置里,C 类都没有被触达。

爬取控制与失败行为

深度不是一个开关。Nutch 里没有 --depth 3 这种参数;深度取决于你跑了多少轮 generate → fetch → parse → updatedb,因为第 R 轮抓的是第 R-1 轮发现的前沿。我的深度链测试把这一点验证得很清楚:

运行轮数到达的最深路径
2/depth/1
3/depth/2
4/depth/3

这套机制很清楚,也很机械,但它意味着深度是脚本里的循环次数,而不是一个单独参数。

再来看一个坑。Nutch 随包默认值是 db.ignore.external.links=false,同时配了一个宽松的 +. URL 过滤规则——这意味着默认爬取会跟着链接跑到种子主机之外。我给一个页面放了一个站内链接和一个指向不同主机的外链,结果爬虫真的抓到了外部主机。两个独立信号都证明了这一点:Nutch 自己的 crawldb 把它标成了 db_fetched,而另一台主机的服务器计数器也记录到了命中。

要把范围限制在站内,必须主动配置,而且下面两种办法都确实有效:

配置crawldb 中是否出现外部主机外部主机服务器命中是否被圈住
db.ignore.external.links=false随包默认db_fetched+1
db.ignore.external.links=true不存在0
regex-urlfilter.txt 中设置主机规则(先写 +^http://127.0.0.1:,再写 -.不存在0

如果你只抓一个站点,在第一次正式运行前就把其中一种方式设好。这里有一个方法学上的提醒:这个测试对本地服务器的负载比较敏感,所以这三行数据来自一次没有其他任务干扰的干净运行。行为本身非常明确,而且由两个独立信号共同支持;但具体行值只是一次干净测试的结果,不是多次平均值。

Sitemap 是另一步。礼貌抓取是开启的——正常爬取会请求 /robots.txt——但 sitemap 本身需要单独执行命令:

方法是否请求了 /sitemap.xml仅存在于 sitemap 中的端点
正常爬取从未请求0/2
显式对 crawldb 运行 bin/nutch sitemap已抓取2/2 条目被注入,召回率完整
katana 的内联 -kf 已知文件模式,同一测试样本,IP 主机上运行未记录0/2

这和那种在抓取过程中内联拉取已知文件的爬虫是不同模型,不过它确实多花一条命令,但能完整完成任务。

另外两个较小的行为也表现稳定。

错误处理: 对一个同时链接到 500 和 404 页面进行爬取时,整个流程依然顺利完成,A 类的四个页面都抓到了,并且对每个失败都分别记录了状态:

页面中链接到的失败响应crawldb 记录状态
500db_unfetched(可重试)
404db_gone

没有任何环节被拖垮。

礼貌性(politeness): 在每个队列只开一个线程时,两次同主机抓取之间的间隔与设置一致:

fetcher.server.delay同主机抓取间隔中位数
1.0 秒1.009 秒(最小 1.006 秒)
0.00.002 秒

这个参数按字面含义生效。随包默认值是 5.0 秒,保守得很,而且对一个设计目的就是去抓陌生服务器的工具来说,这个默认值大概率是对的。

批处理的代价:按秒算

Nutch 的每条命令都会启动一个全新的 JVM。这个事实对时间表现的影响,远大于任何抓取吞吐的因素。

阶段(每轮)中位耗时(秒)
inject(一次)1.81
generate3.93
fetch2.82
parse1.78
updatedb1.81
完整一轮12.14

按一次最轻量的任务阶段来测,JVM 启动加 Hadoop 初始化的“实际每作业下限”大约是 1.77 秒。把它乘上每轮四条命令,再加上最初的 inject,整个爬取的时间结构就变成这样:

工具对 12 页样本做深度 4 爬取进程数
Nutch大约 45 秒(我在两种配置下测到 45.8 秒和 45.0 秒)大约 17 次 JVM 启动,几乎没有哪次真正在做网络工作
katana standard 模式,同一样本大约 13 秒一个进程

这个差距并不是抓取速度造成的;两者请求的页面数量其实差不多。原因在架构:Nutch 的各阶段本来就是按 MapReduce 作业设计的,所以每一阶段都要付固定的进程成本。在一个很小的本地爬取任务里,准备开销反而成了主角。随着任务变大,这个固定成本应该会占比下降,但这次测试并没有测到 Nutch 和 katana 的交叉规模,也没有验证两者比例是否会反转。

优缺点

优点

  • 静态发现是确定性的:HTML A 类 4/4,深度链 3/3,三次重复结果完全一致。
  • parse-js 可以在不使用浏览器的情况下恢复 JavaScript 文件字面量端点(2/2),同时识别调用参数和赋值两种形式。
  • 有两种经过验证的范围控制方式,能把爬取完整限制在站内(db.ignore.external.links 和主机规则 regex-urlfilter)。
  • 通过 bin/nutch sitemap 进行 sitemap 采集,对正常爬取完全错过的端点实现了 2/2 的完整召回。
  • 容错能力不错:500 和 404 都会被分别记录到 crawldb 中,爬取还能继续。
  • 在这次本地测试里,实际同主机间隔与配置的 1.0 秒延迟一致;随包默认是 5.0 秒。
  • Apache-2.0 许可证,仍在积极维护,78 个插件,并且拥有一个持久化 crawldb,能跨轮次跟踪每个 URL 的状态。
  • 本地模式可运行,不需要集群、HDFS,也不需要 Solr。

缺点

  • 在 JDK 24 及以上版本无法运行,SecurityManager 移除会直接触发问题(我在 26.0.1 上实测失败)——随包的 Hadoop 3.4.2 早于上游修复,而那个逃生参数也已经没了,因此固定到 LTS JDK 不是偏好,而是硬性前提。
  • 解压后约 396 MB,包含 188 个库 jar、78 个插件目录、35 个配置文件。
  • 每条命令都要新起 JVM,导致每个阶段约有 1.77 秒固定开销;12 页、深度 4 的爬取大约要 45 秒,而单体二进制爬虫在同样条件下约 13 秒。
  • 随包默认会跟着外链走到其他主机;要只爬一个站点,必须主动设置。
  • http.agent.name 默认是空的,不设置就不会跑。
  • 没有 depth 参数——深度完全靠你自己控制循环轮次。
  • 运行时 DOM 端点在我测试的所有配置里都无法触达,而且替换成可执行 JS 的协议也不是即插即用。
  • 我只在单主机、较小样本的本地模式下做了测试。分布式/HDFS 模式、Solr 索引、hostdb、resume,以及增量重爬调度,都不在这次测试范围内——这里应视为未测试,而不是已验证可用。

适合谁,不适合谁

如果爬取本身就是难点,那么 Nutch 就很值。若你正在搭建搜索索引、要做大范围多域名爬取、需要一个带每个 URL 状态和重试语义的持久化 URL 数据库,或者最终会把工作分布到多台机器上,这就是一套自 Hadoop 之前就一直在干这件事的基础设施。它的插件系统意味着你可以在不 fork 的情况下改协议、解析器、过滤器和评分逻辑。它的礼貌性默认值也相当保守,这说明维护者确实认真考虑过怎样做一个“好邻居”。

如果你想从少量页面里直接拿到结构化数据,那就别选它。Nutch 会抓、会解析,然后给你 crawldb 和 segments,接着等你自己接索引器。如果目标是客户端渲染的单页应用,也别选它——我跑的所有配置里,C 类都没触达。如果你的团队本来就不用 JVM,也别选它,因为这会把 Java 工具链、LTS JDK 锁定,以及 396 MB 的 jars 一起塞进你原本没有这些东西的技术栈里。要是你的工作只是“每周抓一次一个网站,深度四层”,那你花在轮次循环和配置文件上的时间,可能比爬取本身还多。

对大多数在找爬虫的人来说,后面那种情况才是现实。这里并不是批评 Nutch,而是工具和任务不匹配。如果你想看看更广泛的选项,我们的 开源爬虫盘点最佳网页抓取 GitHub 项目 对更轻量的方案有更详细的介绍。

替代方案,以及我们自己的方案放在什么位置

先说公平的一面:Nutch 是免费的、Apache 许可、自托管的,而且你可以永久自用,没有按请求计费。这是实打实的优势,下面任何比较都不会抹掉这一点。

相关评测:Browsertrix Crawler 评测

在开源领域,怎么比较取决于你优化什么。如果你想要一个 Python 框架,强调抓取控制和“先发请求”的思路,Scrapy 对很多项目来说更像对照组;本文没有按同样标准测它的安装体积。如果你想要一个没有浏览器、体积更紧凑的 Go 爬虫,Colly 也是值得评估的形态。如果你的问题不是发现 URL,而是把网页转成适合 LLM 使用的内容,Crawl4AI 面向的是另一层需求。

Thunderbit 这样的托管服务,则把抓取、渲染和抽取都放到 API 后面,而 Nutch 则把爬取状态和基础设施掌握在你自己手里。Thunderbit 没有在这个样本上跑,因此这里比较的是所有权模型,而不是对召回率或动态页面表现的对等断言。

这是一笔所有权和开销之间的交换,而且一点也不含糊。Nutch 给你完全控制权、持久化 crawldb、按设计可扩展到集群,以及零边际成本——代价是 JVM、LTS JDK 锁定、396 MB 的 jars、轮次循环和你自己的索引层。托管 API 的好处是第一次调用就给你结构化输出,也不用你操心基础设施——代价是 按调用计费 和对爬取前沿的控制更少。如果你的任务是“给 5000 万页面建索引”,Nutch 的模型才是正确答案,API 反而荒唐。如果你的任务是“周四前把 200 个商品页里的结构化记录拿出来”,那结论正好相反。

试试 Thunderbit 进行网页数据提取

结论

如果你要长期运行、多域名爬取,而且团队本身就维护 JVM 基础设施,那么 Apache Nutch 值得评估。在这次测试样本上,它的静态发现结果在重复运行中保持一致,parse-js 找到了两个 JavaScript 字面量端点,失败状态也如实保留在 crawldb 中,实际请求间隔与配置延迟一致。

但要诚实评估进入门槛。Nutch 1.22 在这里的 JDK 26.0.1 上失败了;本次评测中真正验证过并可用的 LTS 配置是 OpenJDK 17.0.20,而 Java 21 没有测试。然后再设置 http.agent.name,明确你的爬取范围,并把这次小规模本地测试里观察到的每阶段约 1.77 秒固定下限算进去。这个交换是否值得,取决于爬取时长、覆盖范围以及是否需要持久化状态。

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

常见问题

为什么 Apache Nutch 会报 “getSubject is not supported” 并失败? 在 JDK 24 及以上版本中,JEP 486Subject.getSubject() 变成了无条件抛异常,而随包的 Hadoop 3.4.2 仍然会调用它。因此,第一个 Hadoop 作业在任何页面被抓取之前就会失败,过去的 -Djava.security.manager=allow 也不再能让 VM 启动。请使用我验证过的 Java 17 配置并设置 NUTCH_JAVA_HOME;Java 21 可能也受支持,但本次评测没有在它上面跑完整流程。

Nutch 1.22 应该用哪个 Java 版本? Java 17 是最稳妥的答案——Nutch 自己的 CI 就以它为目标,我在 OpenJDK 17.0.20 上的测试也运行正常。Java 11 对 1.22 也仍然受支持,不过项目已经宣布 1.23 将要求 Java 17。JDK 24 及以上版本都无法运行。用 keg-only 的 Homebrew 安装(brew install openjdk@17)再配合 NUTCH_JAVA_HOME,可以不影响系统默认 JDK。

Nutch 能抓 JavaScript 很重的网站吗? 能,但只能部分做到,而且这个差别很重要。启用 parse-js 插件后,Nutch 能找到那些只存在于已链接 JavaScript 文件中的字符串字面量端点——2/2,而且不需要浏览器。默认插件集合则一个都找不到。但如果端点只会在 JavaScript 执行并修改 DOM 后才出现,那么在我测试的任何静态配置里都无法触达;而把协议换成 HtmlUnit 也不是一次就能直接跑通的改动。对于客户端渲染应用,你要么准备好 JS 执行型协议并投入真正的配置工作,要么直接换工具。

Nutch 需要安装 Hadoop 和 Solr 吗? 不需要。本地模式使用 Hadoop 的 LocalJobRunner 进程内执行——没有集群,没有 HDFS 守护进程,也没有 YARN——完整的 inject → generate → fetch → parse → updatedb 流程在一台机器上就能跑,不需要额外安装别的东西。Solr 通常是索引去向,但抓取本身并不依赖它。不过要注意,Hadoop jars 是打包自带的(13 个,版本 3.4.2),这也正是 JDK 兼容性问题存在的原因。

怎么阻止 Nutch 去抓别的网站? 要显式设置,因为随包默认不会帮你限制。Nutch 1.22 以 db.ignore.external.links=false 和宽松的 URL 过滤规则发布,在我的测试里,默认爬取确实跟着外链抓到了不同主机。你可以在 nutch-site.xml 中设置 db.ignore.external.links=true,或者在 conf/regex-urlfilter.txt 里加主机规则(例如先写 +^https://example\.com/,再写 -.)。这两种方式都能把爬取完全限制在站内,这一点已通过 Nutch 自己的 crawldb 和另一台服务器的请求日志共同验证。

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