Firecrawl 是一个把网页抓取、JavaScript 渲染、内容清洗和结构化输出打包到一起的开源爬虫工具,核心能力是:输入一个 URL,输出一份干净、可以直接喂给大模型的 Markdown 内容。以前做 RAG、AI 搜索或者文档知识库,最烦人的不是数据源少,而是网页抓回来以后要花大量时间洗数据,导航栏、广告位、弹窗、动态加载的内容、各种样式标签全混在一起。Firecrawl 把这些处理内置了,所以这两年做 AI 应用的团队用它的频率非常高。这篇文章我会按一条完整的落地路线来讲:先搞清楚它究竟解决什么问题,再理清云端 API、免费额度和本地部署三条路怎么选,然后从单页抓取一步步跑到整站爬取和结构化提取,最后把常见报错和排查链路也列出来。
1. Firecrawl 解决什么问题:网页内容到 LLM 可用格式的最后一公里
1.1 普通爬虫抓回来的 HTML,为什么没法直接用
很多人会想:网页抓取不是很简单吗,用 Python 的 Requests 拿到 HTML,再用 BeautifulSoup 提取正文就行了。如果你只抓静态官网,确实可以。但只要站点稍微复杂一点,问题就来了。
第一是动态渲染。现在大量站点是 Vue、React 或 Nuxt 做的,正文内容要通过 JavaScript 请求接口后再渲染到页面上。直接用普通 HTTP 请求拿到的 HTML 里,往往只有一个空的页面骨架和一段脚本,正文一个字都没有。这种情况你只能上 Playwright 或 Puppeteer 这类浏览器自动化工具,自己控制浏览器去渲染页面,再等网络请求完成。
第二是页面噪音。就算你把页面渲染出来了,里面还有网站导航、侧边栏推荐、页脚链接、Cookie 弹窗、广告位、相关文章模块。这些内容对浏览器用户是正常的,但对大模型来说全是干扰。如果不处理干净,切分出来的文本块质量非常差,检索准确率也会明显下降。
第三是格式问题。大模型应用通常需要干净的 Markdown 或纯文本,而不是一堆 div、span、class 嵌套的 HTML。你当然可以写正则或者 XPath 去抽取,但每个站的页面结构都不一样,写一套规则只能对付一个站,换一个站又要重新调。
我自己最早做采集脚本时就是这样:Requests 抓静态站还行,遇到 Vue 写的文档站就抓不到正文;后来换 Playwright,能渲染了,但又要为每个站单独写内容提取规则。这个痛点不是“抓不到”,而是“抓到了但没法直接用”。
1.2 Firecrawl 的核心能力拆解
Firecrawl 把上面这些环节打包成一组 API,核心功能可以分成五块:
| 功能 | 对应接口 | 解决什么问题 |
|---|---|---|
| 单页抓取 scrape | POST /v1/scrape | 抓取单个 URL,转成 Markdown |
| 整站爬取 crawl | POST /v1/crawl | 从入口 URL 开始,按链接关系爬完整站 |
| 搜索抓取 search | POST /v1/search | 先搜索互联网,再把结果页转成 Markdown |
| 链接映射 map | POST /v1/map | 列出指定站点下的所有 URL 清单 |
| 结构化提取 extract | POST /v1/extract | 按 Prompt 从页面中提取 JSON 结构化数据 |
scrape 是最常用的起点,解决单个页面的问题。crawl 解决的是“我有一整个文档站或资讯站,想一次性全抓下来”的问题。map 可以在爬全站之前先摸清楚站点规模。search 适合做 AI 搜索类应用。extract 则让输出从“一篇 Markdown”变成“一条结构化记录”。
需要强调的是,这几个能力不是孤立的,实际使用时经常组合。比如先 map 看站点有哪些页面,再 crawl 批量抓取,最后 extract 提取关键字段。
1.3 适合谁用,不适合谁用
先说适合的人。做 RAG 知识库采集的、做 AI 智能体网页检索工具的、整理文档站和博客站做二次分析的、需要把竞品页面定期存档做内容监控的,这几个场景都很合适。Firecrawl 的最大价值是帮你把“清洗网页”这层重复劳动省掉,让你把精力放在业务逻辑上。
不太适合的场景也有。如果你需要每天抓几十万个页面,而且对成本极其敏感,那需要认真算一笔账,云端的按量计费不一定划算。如果你需要抓的是强反爬、强验证码的站点,Firecrawl 能帮你一部分,但不能解决所有商业级反爬难题。如果你希望完全掌控每一步的并发、调度、失败重试、存储逻辑,那么把它当底层组件用,而不是当成一个黑盒来用,会更合适。
2. 动手前先理清运行条件:云端 API、免费额度、本地部署三条路
2.1 云端 API 的基本门槛
Firecrawl 的使用方式很直接:去官网注册账号,拿到一个以 fc- 开头的 API Key,然后调用远程接口。云端方案的好处是 JavaScript 渲染、队列调度、代理池、内容清洗这些事都由官方托管处理,你不需要自己维护浏览器服务。
使用云端 API 只需要满足几个条件:
- 能正常访问 Firecrawl 的 API 服务,也就是 api.firecrawl.dev 这个地址。
- 有一个有效账号和 API Key。
- 调用时把 Key 放在 Authorization 请求头里。
我个人建议第一步先用云端 API 做验证,不要一上来就自己部署。原因很简单:云端能帮你确认“Firecrawl 本身能不能满足需求”。如果云端都抓不到的内容,自托管大概率也抓不到,因为核心渲染和清洗逻辑是同一套。
2.2 免费额度到底够不够用
和 Firecrawl 相关的搜索热词里,“免费额度”出现频率很高,这确实是大多数人最关心的点。新账号注册后一般会送一定量的免费额度,这个额度足够用来跑通整个流程。
按我注册时的情况,免费额度以 credit 为单位计量,数量大约在几百个这个量级。一次 scrape 通常消耗一个 credit,crawl 是按实际抓取的页面数量扣费,search 按返回的结果数扣费。不同活动的赠送政策、不同时段的计费规则可能会有差别,所以具体数值要以官网注册页面和定价页面显示为准。
免费额度够干什么?够你抓十几篇到几十篇文章,够你跑一次小规模的整站爬取,够你把所有 API 都试一遍,确认输出格式是否满足需求。但如果你要持续每天抓几百个页面,免费额度很快就会用完。
这里有一个容易忽略的点:额度消耗不是按“调用次数”简单算的。一个 crawl 任务如果设置了很大的 limit,一次任务就可能扣掉几十个 credit。所以控制任务范围特别重要,这一点后面详细说。
2.3 本地部署需要哪些前置条件
如果你不想被额度绑住,可以自托管。Firecrawl 是开源项目,仓库里提供了 Docker 部署方式。自托管的大致组件包括:
- Firecrawl API 服务,负责接收请求和调度任务。
- Worker 服务,负责实际执行抓取和内容清洗。
- Playwright 浏览器服务,负责渲染 JavaScript 页面。
- Redis,负责任务队列和缓存。
这些服务可以一键用 docker compose 启动,但第一次部署时需要注意网络、端口和依赖版本。官方仓库的 README 会给出环境变量清单,包括 API Key、Redis 连接地址、Playwright 服务地址等。
自托管对机器配置的要求不算高,主要消耗内存,不太吃 GPU。一台 4 核 8G 内存的服务器可以跑小型采集任务,但如果同时开很多并发任务,Redis 队列和 Playwright 浏览器实例会吃掉不少内存,需要根据任务量调整。
2.4 三条路到底怎么选
| 方案 | 优点 | 代价 |
|---|---|---|
| 云端免费额度 | 零成本、快速验证、不需要运维 | 额度有限,只适合测试和小批量 |
| 云端付费 | 稳定、有代理池、省心 | 按量计费,量大会持续花钱 |
| 本地自托管 | 没有额度限制、数据在自己手里 | 要自己维护服务、处理反爬和 IP 问题 |
我的建议是:学习期和原型验证用云端免费额度,小规模生产可以继续用云端付费,如果是高频大规模采集且团队有运维能力,再考虑自托管。不要一开始就部署,先把需求验证清楚,省得白忙。
3. 最小流程:先跑通一次单页面抓取
3.1 注册账号并拿到 API Key
先做最小验证。注册账号之后,进入 Dashboard 找到 API Key,复制出来。注意这个 Key 相当于账号凭证,不要写到公开仓库里。
拿到 Key 以后,不要急着写业务代码,先想清楚两件事:第一,Firecrawl 返回的 Markdown 质量是不是你想要的;第二,它处理动态页面和复杂站点的能力够不够。这两件事用一条 API 请求就能验证。
3.2 先不用 SDK,直接用 curl 验证
为什么先用 curl 而不是直接写 Python?因为 curl 能隔离掉 SDK 版本、依赖安装、代理配置这些变量。如果 curl 返回正常,说明网络和 Key 没问题;如果 curl 都报错,那就先排查网络和 Key,不要怪 SDK。
curl -X POST https://api.firecrawl.dev/v1/scrape \ -H "Content-Type: application/json" \ -H "Authorization: Bearer fc-你的API_KEY" \ -d '{ "url": "https://example.com", "formats": ["markdown"] }'正常返回的结构大致是:
{ "success": true, "data": { "markdown": "# Example Domain\nThis domain is for use...", "metadata": { "title": "Example Domain", "description": "...", "language": "en" } } }判断成功的标准有三个:success 为 true、markdown 字段不为空、metadata 里有页面标题。只要这三个条件满足,说明 Firecrawl 的链路是通的。
3.3 用 Python SDK 跑同样的事
curl 验证通过之后,再用 SDK 做正式开发。安装命令很简单:
pip install firecrawl-py然后写一个最简脚本:
from firecrawl import FirecrawlApp app = FirecrawlApp(api_key="fc-你的API_KEY") result = app.scrape_url( "https://example.com", params={ "formats": ["markdown"], "onlyMainContent": True, } ) print(result.get("markdown", "")[:500])这里我把 onlyMainContent 设成了 True。这个参数的作用是过滤掉导航、页脚、侧边栏等非正文内容,只保留页面主体区域。如果你要抓的内容是文章或文档,建议直接开启。
需要注意,不同 SDK 版本的参数命名可能有细微差别。比如有些版本里爬取参数是 params,有些版本里是 options。遇到报错先看对应版本的 SDK 文档,别照着旧版本硬套。
3.4 常用参数说明
scrape 接口参数比较多,但核心就这几个:
| 参数 | 作用 | 建议 |
|---|---|---|
| formats | 返回格式,如 markdown、html、rawHtml、links、screenshot | RAG 场景用 markdown |
| onlyMainContent | 是否只保留页面主体内容 | 抓文档和文章时建议 True |
| waitFor | 等待指定毫秒数,让 JS 渲染完成 | 动态站点设 2000 到 5000 |
| timeout | 单次请求超时时间 | 网络不稳定时适当调大 |
| includeTags | 只提取指定 HTML 标签内容 | 内容聚焦时可用 |
| excludeTags | 排除指定 HTML 标签内容 | 可用来去掉广告区域 |
| headers | 自定义请求头 | 部分站点需要携带特定 UA |
我一般会先只用 markdown 加 onlyMainContent 跑一次,看输出是否干净。如果正文缺失,再考虑加 waitFor 或者调整 tags 参数。不要一上来就把参数堆满,先最小条件跑通,再逐步加。
3.5 输出质量怎么判断
抓回来的 Markdown 不一定直接用,要检查三件事:
- 正文是否完整。把输出和浏览器里看到的页面对比一下,看有没有缺段落、缺标题。
- 噪音是否够少。如果导航和页脚都进 Markdown 了,说明 onlyMainContent 没有生效,或者这个站的结构比较特殊。
- 格式是否正常。标题层级、列表、代码块、表格是否保留正确。Firecrawl 对多数站点处理得不错,但遇到极端布局的页面,Markdown 结构还是可能乱。
如果发现输出不理想,不要立刻怀疑工具不行。先用 rawHtml 格式把原始 HTML 拉下来,看看页面本身长什么样,再判断是渲染问题还是提取问题。
4. 从单页到整站:crawl 任务的参数与队列逻辑
4.1 crawl 和 scrape 的区别是什么
scrape 是单页操作,请求发出后同步等待结果返回。crawl 是异步任务:你先提交一个入口 URL 和爬取参数,服务端创建任务,返回一个任务 ID,然后你通过这个 ID 轮询任务状态,直到任务完成。
为什么 crawl 要做成异步?因为整站爬取可能涉及几十上百个页面,每个页面都要渲染、清洗、转换,单次 HTTP 请求根本等不了那么久。异步任务加队列,是这类系统的标准设计。
所以用 crawl 时的核心思路是:提交任务、拿任务 ID、轮询状态、任务完成后拉取结果。不要指望一次请求直接返回所有页面。
4.2 crawl 的关键参数
用 crawl 时,我最关心的参数是以下四个:
crawl_result = app.crawl_url( "https://docs.example.com", params={ "maxDepth": 2, "limit": 50, "formats": ["markdown"], "onlyMainContent": True, } ) job_id = crawl_result.get("jobId") or crawl_result.get("id") print("任务 ID:", job_id)- maxDepth:爬取深度。0 表示只抓入口页,1 表示抓入口页和所有直接链接的页面,2 表示再往下一层。
- limit:最多抓取页面上限。这是保护额度的最重要参数。
- ignoreSitemap:是否忽略站点地图。有些站点 sitemap 特别大,不设 limit 的话会一直抓下去。
- deduplicateSimilarURLs:是否去重相似 URL。像带排序参数、翻页参数的链接,去重后能省不少额度。
我建议先设一个小 limit,比如 10,跑通流程后再放大。不要一上来就设 500,等任务卡住或者额度被扣完再后悔。
提交任务后,需要轮询状态:
import time status = app.check_crawl_status(job_id) while status.get("status") in ["active", "pending"]: time.sleep(5) status = app.check_crawl_status(job_id) if status.get("status") == "completed": pages = status.get("data", []) for page in pages: url = page.get("metadata", {}).get("url") markdown = page.get("markdown", "") print(url, len(markdown))这段是示意性写法,具体返回字段以你用的 SDK 版本为准。核心逻辑就是:拿到任务 ID,循环检查,状态变成 completed 之后处理结果数组。
4.3 crawl 任务真正容易踩的坑
第一个坑是并发提交太多。不要对同一个站点同时开十几个 crawl 任务,这会导致额度快速消耗,也会让站点负载变大,更容易触发反爬。
第二个坑是 limit 范围没控制好。有些站点结构很复杂,链接互相交叉,爬取数量可能远超你预期。提交之前先用 map 接口看一下站点规模,再确定 limit 值。
第三个坑是结果落盘。crawl 返回的是内存里的一个数组,如果任务中断或者进程退出,结果就丢了。正式使用时,每轮询到 completed 状态,就应该把页面数组写入文件或数据库。
第四个坑是页面顺序。crawl 返回的页面顺序不保证和站点目录结构一致,不要依赖顺序做业务逻辑。按页面 URL 建立索引更靠谱。
第五个坑是登录墙。如果站点需要登录才能看到正文,crawl 默认情况下是抓不到内容的。可以先试试直接访问是否能看到正文,看不到的话,就需要考虑带 Cookie 或 header,或者放弃这个站点。
5. 搜索、映射与结构化提取:把抓取变成数据管线
5.1 map 先摸清站点规模
在跑 crawl 之前,我建议先用 map 接口看站点结构。map 的作用是列出某个站点下所有能被发现的 URL。
curl -X POST https://api.firecrawl.dev/v1/map \ -H "Content-Type: application/json" \ -H "Authorization: Bearer fc-你的API_KEY" \ -d '{"url": "https://docs.example.com"}'返回结果会包含一个 links 数组。你可以数一下 links 数量,看这个站点的页面规模是几十还是几千。如果 links 数量超过 1000,而你的免费额度只有几百个 credit,那 crawl 之前就要想清楚:是只爬其中一部分,还是改用筛选条件缩小范围。
5.2 search 解决“先找再抓”的场景
search 接口适合做 AI 搜索类应用。它先执行一次搜索,然后把搜索结果中的网页转成 Markdown 返回。这样你得到的不只是一串链接,而是已经清洗好的内容。
curl -X POST https://api.firecrawl.dev/v1/search \ -H "Content-Type: application/json" \ -H "Authorization: Bearer fc-你的API_KEY" \ -d '{ "query": "firecrawl markdown scraping", "limit": 5 }'返回结果里每个条目会包含页面 URL、标题、描述和 Markdown 内容。这个功能做合规的公开信息检索是很好用的,但要注意:搜索结果经常包含同一站点的多个页面,如果只需要最新内容,可以按时间排序并做去重。
5.3 extract 提取结构化字段
extract 接口解决的是“从网页里抽出结构化数据”的问题。你给它一批 URL 和一段 Prompt,它返回的是 JSON,而不是 Markdown。
curl -X POST https://api.firecrawl.dev/v1/extract \ -H "Content-Type: application/json" \ -H "Authorization: Bearer fc-你的API_KEY" \ -d '{ "urls": ["https://example.com/news/1", "https://example.com/news/2"], "prompt": "提取每篇文章的标题、作者、发布时间和正文摘要,输出 JSON 数组" }'使用 extract 时,Prompt 写得越具体,字段越明确,返回结果越稳定。比如你要提取文章发布时间,就应该在 Prompt 里明确说“时间格式为 YYYY-MM-DD”。如果 Prompt 描述模糊,模型可能自由发挥,字段名和格式就不统一了。
5.4 组合出一个 RAG 数据采集管线
实际做 RAG 数据采集,我常用的组合是:
- 先用 map 拿到站点 URL 清单。
- 根据清单筛选出需要的分区,构造一个待抓取 URL 列表。
- 用 crawl 或逐个 scrape 抓取页面,保存 Markdown。
- 用 extract 对每篇页面提取标题、日期、作者等结构化字段。
- 把 Markdown 和结构化字段一起存入向量数据库或对象存储。
这个流程跑通后,还可以加一层定时调度。Firecrawl 本身没有内置定时任务,你需要用外部调度器,比如 Linux 的 cron 或者 CI 服务,定期触发一次采集任务,然后对比上次结果,只增量更新变化页面。增量更新能省掉大量重复抓取成本。
6. 免费额度怎么用才划算
6.1 先理解额度是怎么扣的
Firecrawl 的免费额度按 credit 计量。一次 scrape 消耗一个 credit 左右,crawl 按实际抓取页面数量扣,search 按返回结果数量扣,extract 也会消耗较多 credit。不同页面类型可能还有差别,比如需要长时间渲染的页面消耗会更高。
这里有一个容易被忽略的点:crawl 任务即使中途失败,已经抓取过的页面也会扣费。所以在提交大任务前,一定要先用小 limit 测试,确认目标站点能稳定抓取,再放大规模。
免费额度的具体数值和使用情况,以官网 Dashboard 显示为准。不用过于依赖“网上说送多少”的说法,注册后直接看后台最准确。
6.2 省额度的几个实际操作
我总结了几条能实际省 credit 的策略:
第一,先 map 再 crawl。map 的消耗远低于 crawl,先看清站点规模,避免全站盲抓。
第二,给 crawl 设置合理的 limit。limit 是硬性上限,能防止站点结构异常时无限爬下去。对于一般文档站,limit 设 50 到 100 已经不少了。
第三,优先抓高价值页面。如果你的知识库只需要文章正文,就不应该把标签页、作者页、归档页、登录页都抓进来。这些页面内容重复度高,浪费额度。
第四,开启 onlyMainContent。虽然它不直接影响扣费数量,但能减少返回内容的体积,让后续处理更省事。
第五,做缓存和增量更新。已经抓过的 URL 不要重复抓。采集脚本里维护一个 URL 到内容哈希的映射,发现页面没变就跳过。
第六,本地自托管跑普通站点,云端额度留给需要代理池和复杂渲染的站点。这样能把免费额度的效益放大。
6.3 额度超限会怎样
额度用完后,调用会报错,通常是认证相关错误或 429 类限流错误。判断方式很简单:控制台看返回码,去 Dashboard 看剩余额度。
遇到超限不要慌,先把任务队列停掉,避免反复重试继续消耗。如果只是偶尔超限,可以等额度刷新,或者换一个账号测试。如果是生产环境,就必须购买付费套餐或者切到自托管。
免费额度适合验证和不定期小批量采集,不适合长期依赖。把它当成“试用装”,不要当成生产资源。
7. 常见报错与排查链路
7.1 先按现象分类,再逐层排查
我在使用过程中遇到的报错,基本可以归成这几类:
| 现象 | 常见原因 | 排查方向 |
|---|---|---|
| 返回 401/403 | API Key 无效、额度超限 | 检查 Key、后台剩余额度 |
| 返回 429 | 请求过于频繁 | 加间隔、减小并发、看限流响应头 |
| markdown 为空 | 页面需要 JS 渲染、被拦截 | 调大 waitFor、抓 rawHtml 对比 |
| 返回内容缺正文 | 登录墙、跳转页、页面结构特殊 | 查看原网页、确认 URL 是否真实 |
| crawl 长时间 pending | 站点响应慢、任务积压 | 等待、查看后台任务状态 |
| 本地部署抓取失败 | Redis、Playwright 服务没起来 | 看容器日志、检查服务健康状态 |
排查时不要直接改代码。先看返回的响应体,Firecrawl 一般会在错误信息里说明原因。再看你的输入 URL,很多问题根本不是 Firecrawl 的问题,而是 URL 本身就是登录页或者 404 页面。
7.2 抓到的内容和浏览器看到的不一样
这种情况经常出现,原因有几种:
- 网站根据登录状态返回不同内容。
- 网站根据地区或 IP 返回不同内容。
- 网站有 A/B 测试,不同访客看到不同版本。
- 页面内容是通过多次异步请求加载的,等待时间不够。
遇到这种情况,先手工打开网页确认内容是否稳定。然后尝试在请求里带上对应的 Cookie 或 header。Firecrawl 支持自定义 headers,你可以把浏览器里的 Cookie 复制过来测试。
不过我要提醒一点:携带 Cookie 抓页面,只适合你自己有权限访问的站点。抓公共站点时,不要试图绕过登录、验证码等访问控制。做内容采集要遵守目标站点的服务条款和 robots 协议。
7.3 本地部署常见问题
自托管遇到的典型问题:
- Redis 没启动,任务提交后一直排队不执行。
- Playwright 浏览器服务没启动,页面渲染失败。
- 环境变量缺失,服务启动报错。
- 内存不足,多开几个浏览器实例后进程被系统杀掉。
排查顺序是先看所有服务的容器是否存活,再看日志里有没有 Redis 连接错误,最后用小量测试确认渲染正常。自托管不是装上就能跑完的,环境变量和依赖版本要严格按文档来。
7.4 通用排查顺序
如果问题不确定,我建议按这个顺序排查:
- 看返回码和响应体。先确认 Firecrawl 是否正常处理了你的请求。
- 看目标 URL 是否可以直接访问。把 URL 粘到浏览器里,看内容是否正常。
- 看原始 HTML。用 formats 里的 rawHtml 返回,看页面源码里有没有正文。
- 看日志。如果是自托管,看 API 服务、Worker、Playwright 各自的日志。
- 看参数。确认 waitFor、timeout、limit 这些参数是否和页面情况匹配。
- 看资源。如果是自托管,确认 CPU、内存、磁盘是否够用。
这个顺序能解决大部分问题。最忌讳的是跳过前面几步,直接去调参数。很多时候,调半天参数,最后发现是 URL 写错了,或者 API Key 复制多了个空格。
8. 云端托管还是自托管:生产环境怎么选
8.1 云端托管的价值在哪里
云端方案最大的价值不是“不用部署”,而是“不用维护反爬策略”。Firecrawl 团队维护了代理池、浏览器版本、渲染服务,这些在自托管时都是要自己处理的。
第二个价值是稳定性。云端有完整的任务队列和重试机制,你不用操心 Redis 挂掉、浏览器崩溃、磁盘写满这些问题。对于小团队来说,省掉的运维时间价值很高。
第三个价值是响应速度。云端服务的出口 IP 和渲染资源是现成的,你不用买服务器、配代理,注册完就能跑。
8.2 自托管的真实成本
自托管的成本不只是服务器费用。你要维护的东西包括:
- Docker 镜像的版本更新。
- Playwright 浏览器及系统依赖的更新。
- 反爬策略:目标站点会限制访问频率,你需要自己处理 IP 封禁和访问间隔。
- 任务队列的监控:Redis 积压、任务失败、重试策略都要自己盯。
- 内容清洗逻辑的版本维护。
如果只是个人学习和原型验证,自托管更像负担。如果是团队生产环境,每天要抓大量页面,且需要控制数据不出内网,那么自托管有其合理性,但前提是团队有人能扛住这些运维成本。
8.3 我的建议
我更推荐分阶段走:
- 第一个阶段:用云端免费额度跑通全部功能,验证输出质量。
- 第二个阶段:购买云端最低档套餐,跑一个月真实业务,统计日均页面数和成本。
- 第三个阶段:如果成本可控,继续用云端;如果成本很高,再考虑自托管或混合模式。
混合模式也很常见:普通站点用自托管,难抓的站点用云端。这样能平衡成本和成功率。
最忌讳的是跳过验证直接上量。先抓 10 个页面,再看 10 个页面的质量,再决定抓 1000 个页面,这是做任何采集任务都通用的节奏。
最后留一个实际经验。Firecrawl 这类工具真正落地时,最核心的问题往往不是“能不能抓”,而是“抓完之后怎么持续维护”。站点改版、页面结构变动、链接失效、额度消耗,这些都是长期要面对的。我现在的做法是:所有抓回来的 Markdown 都落盘到本地目录,按域名和日期分目录存放,再建一个简单的索引文件,记录 URL、抓取时间、内容长度和状态。这样即使后续 Firecrawl 某个版本行为变了,我至少不会丢掉已经抓到的数据。
如果你正在做 RAG 或 AI 搜索相关的采集工作,先用免费额度把单页抓取和整站爬取各跑一遍,确认输出质量能接受,再决定要不要上量。很多问题不是工具能力不够,而是目标页面本身有登录墙、结构特殊,或者任务范围没有控制好。把这些边界摸清楚,Firecrawl 会是一个相当好用的网页数据入口。