首页
/ Langflow lfx-firecrawl 扩展包详解:Firecrawl Scrape、Crawl、Map、Search 四个组件的安装、开发与迁移

Langflow lfx-firecrawl 扩展包详解:Firecrawl Scrape、Crawl、Map、Search 四个组件的安装、开发与迁移

2026-09-06 13:49:45作者:姚月梅Lane

本文围绕 Langflow 仓库中的 lfx-firecrawl 独立扩展包(Extension Bundle)展开,讲清楚它的安装与注册机制、四个 Firecrawl API 组件(Scrape、Crawl、Map、Search)的输入/输出契约与默认参数、面向 firecrawl-py v2 SDK 的参数适配层,以及旧版流程(flow)的自动迁移机制。读完后你可以直接在 Langflow 服务器中启用该扩展包,把网页抓取、整站爬取、站点地图枚举和网络搜索接入到自己的工作流或 Agent 工具中,并能看懂组件源码中 v1→v2 SDK 的关键字映射逻辑。

一、扩展包定位:从内建组件到独立 Bundle

Firecrawl 是 Langflow 工作流里用于"网页转结构化数据"的外部服务:把 URL 抓取成 Markdown/JSON、把整个站点爬取成数据集、枚举站点链接、或直接跑一次带位置偏置的网络搜索。这四个能力在 Langflow 早期是内建组件(位于 lfx.components.firecrawl.*),如今被抽取成独立分发的扩展包 lfx-firecrawl,基于 firecrawl-py v2 SDK 构建,源码位于 src/bundles/firecrawl 目录。

包的元数据定义在 pyproject.toml 中,关键事实如下:

  • 包名 lfx-firecrawl,当前版本 0.1.1,要求 Python >=3.10,<3.15,MIT 协议;
  • 运行依赖只有两项:lfx>=1.12.0.dev0,<2.0.0(提供 BUNDLE_API 组件基类与输入/输出定义)和 firecrawl-py>=4.0.0,<5.0.0(v2 版 SDK);
  • 通过 [project.entry-points."langflow.extensions"] 声明 lfx-firecrawl = "lfx_firecrawl"——这就是 README 中"通过 langflow.extensions entry-point 自动注册"的具体落点;
  • 构建系统为 hatchling,[tool.hatch.build.targets.wheel] 显式打包 src/lfx_firecrawl 包以及 extension.jsoncomponents/**/*.py,保证 importlib.metadata.files() 能定位到清单文件。

运行时清单是 extension.json,它声明了扩展包 ID lfx-firecrawllfx.compat 兼容域(["1"])以及一个名为 firecrawl 的 bundle,路径指向 components/firecrawl。加载器据此把组件注册到命名空间 ID ext:firecrawl:<Class>@official 下——这一点在包入口 init.py 的模块 docstring 中也有明确说明。

{
  "$schema": "https://schemas.langflow.org/extension/v1.json",
  "id": "lfx-firecrawl",
  "version": "0.1.1",
  "name": "Firecrawl",
  "description": "Firecrawl components (Scrape, Crawl, Map, and Search APIs) as a standalone Langflow Extension Bundle.",
  "lfx": {
    "compat": ["1"]
  },
  "bundles": [
    {
      "name": "firecrawl",
      "path": "components/firecrawl"
    }
  ]
}

二、安装与启用

README 的 Install 一节,安装只需一条命令:

pip install lfx-firecrawl

由于 Bundle 通过 langflow.extensions entry-point 自动注册,安装后需要重启 Langflow 服务器;重启后四个组件会出现在组件面板(palette)的 firecrawl 分组下。这里可以补充一个实现细节:pyproject.toml 中针对 editable 安装留了兜底逻辑——如果开发态安装只暴露 dist-info 条目,加载器会回退到 entry-point 去找清单,因此本地 pip install -e . 同样能被正常发现。

三、四个组件的输入输出契约

包入口 init.py 导出四个公开类:FirecrawlScrapeApiFirecrawlCrawlApiFirecrawlMapApiFirecrawlSearchApi,它们分别位于 components/firecrawl/ 下的四个模块中。四个组件共享一个公共模式:

  • 都继承自 lfx.custom.custom_component.component.Component
  • 都带一个必填的 api_keySecretStrInputpassword=True,以密码形式在 UI 中脱敏展示);
  • 都在方法体内惰性 from firecrawl import Firecrawl 导入 SDK,导入失败时抛出带提示信息的 ImportError(提示用 pip install firecrawl-py 安装);
  • 都把 SDK 返回的 v2 类型化对象(Typed Object)通过 model_dump() 序列化为 dict,包进 lfx.schema.data.Data 输出,供下游组件消费;
  • 关键入参(URL、Query 等)都标记了 tool_mode=True,意味着这些组件可以被当作 Agent 的工具调用,且这些字段会暴露为工具参数。

下面逐个拆解。

3.1 Firecrawl Scrape API(单页抓取)

实现见 firecrawl_scrape_api.py,组件展示名 "Firecrawl Scrape API",描述为 "Scrapes a URL and returns the results."。

输入名 展示名 类型 说明
api_key Firecrawl API Key SecretStrInput,必填 调用 Firecrawl API 的密钥
url URL MultilineInput,必填,tool_mode 要抓取的 URL
timeout Timeout IntInput 请求超时,单位毫秒
scrapeOptions Scrape Options DataInput 随请求发送的页面选项(JSON 结构)
extractorOptions Extractor Options DataInput 结构化抽取选项

执行逻辑(scrape 方法)有三个值得注意的默认值处理:

  1. formats 默认设为 ["markdown"],即默认输出 Markdown 格式;
  2. onlyMainContent 默认为 True,只抓取主体内容;
  3. timeout 仅在你填了值时才注入参数。

v2 SDK 的一个重要变化体现在结构化抽取上:v1 时代抽取是独立选项,v2 则在 scrape 调用里通过 formats 列表中追加一个 {"type": "json", ...} 条目来请求结构化输出。源码中的处理是:若 extractorOptions 非空,就把它转换后合并进 formats。最终调用 app.scrape(self.url, **kwargs),v2 返回类型化 Document 对象,再 model_dump() 成 dict 输出为 JSON(data)。

3.2 Firecrawl Crawl API(整站爬取)

实现见 firecrawl_crawl_api.py

输入名 展示名 类型 说明
api_key Firecrawl API Key SecretStrInput,必填 密钥
url URL MultilineInput,必填,tool_mode 要爬取的起始 URL
timeout Timeout IntInput 请求超时(毫秒)
idempotency_key Idempotency Key StrInput 可选幂等键,保证请求唯一性
crawlerOptions Crawler Options DataInput 爬取选项
scrapeOptions Scrape Options DataInput 页面抓取选项

crawl 方法内置了一组默认值,这是该组件"开箱即用"行为的来源:

params.setdefault("maxDepth", 2)                    # 默认爬 2 层
params.setdefault("limit", 10000)                   # 默认最多 1 万个 URL
params.setdefault("allowExternalLinks", False)      # 默认不爬站外链接
params.setdefault("allowBackwardLinks", False)      # 默认不反向爬取
params.setdefault("ignoreQueryParameters", False)   # 默认不忽略 query 参数
scrape_options_dict.setdefault("onlyMainContent", True)

随后进入 v1→v2 的关键字重命名(详见第四节),并把 scrapeOptions 构造为 v2 的类型化 ScrapeOptions 对象挂到 scrape_options 参数上。调用 app.crawl(self.url, **kwargs) 时,v2 SDK 会轮询到任务完成并返回类型化 CrawlJob 对象,组件再以 {"results": crawl_job.model_dump()} 的形式输出 JSON(data)。

3.3 Firecrawl Map API(站点链接枚举)

实现见 firecrawl_map_api.py

输入名 展示名 类型 说明
api_key Firecrawl API Key SecretStrInput,必填 密钥
urls URLs MultilineInput,必填,tool_mode 支持逗号或换行分隔的多个 URL
ignore_sitemap Ignore Sitemap BoolInput 为 true 时忽略 sitemap.xml
sitemap_only Sitemap Only BoolInput 为 true 时只返回 sitemap 中的链接
include_subdomains Include Subdomains BoolInput 为 true 时同时扫描子域名

map 方法的处理流程:

  1. 校验 urls 非空,并把换行统一替换为逗号后逐段 strip,得到 URL 列表(即"逗号或换行分隔"的解析规则在源码中可验证);
  2. sitemap 处理体现了 v2 的枚举化改造:v1 的两个独立布尔开关 ignoreSitemap/sitemapOnly 在 v2 中合并为单一 sitemap 模式参数——sitemap_only=True 映射为 sitemap="only"ignore_sitemap=True 映射为 sitemap="skip"sitemap_only 优先级更高),两者都为 false 时不传该参数,使用默认混合行为;
  3. 对每个 URL 调用 app.map(url, **kwargs),v2 返回类型化 MapData 对象,其 .links 是类型化链接列表;组件把各 URL 的结果 links 合并成一个 combined_links,最终输出 {"success": True, "links": combined_links} 形式的 JSON(data)。

3.4 Firecrawl Search API(网络搜索)

实现见 firecrawl_search_api.py

输入名 展示名 类型 说明
api_key Firecrawl API Key SecretStrInput,必填 密钥
query Query MultilineInput,必填,tool_mode 搜索查询词
limit Limit IntInput,默认 5 最多返回的结果数
location Location StrInput,advanced 搜索位置偏置(如国家/地区)

search 方法先校验 query 非空,再把 limitlocation 按需注入 kwargs 调用 app.search(self.query, **kwargs)。v2 返回按来源分组的类型化 SearchData 对象,组件 model_dump() 后直接作为 JSON(data)输出。注意 location 被标为 advanced=True,即默认折叠在高级选项里,limit 有内置默认值 5。

四、v1 → v2 SDK 适配层:camelCase 到 snake_case 的翻译

四个组件共享的核心适配逻辑是一个正则驱动的关键字转换器(见 Scrape 模块 L13-L23 与 Crawl 模块中的同名定义):

_CAMEL_TO_SNAKE_RE = re.compile(r"(?<!^)(?=[A-Z])")

def _to_snake_case_kwargs(params: dict) -> dict:
    return {_CAMEL_TO_SNAKE_RE.sub("_", key).lower(): value for key, value in params.items()}

背景是:Firecrawl v1 API/SDK 惯例使用 camelCase 参数名,而 v2 SDK 的 Python 接口要求 snake_case 关键字参数。组件允许用户以 v1 风格(camelCase)填写 options 数据,转换器统一转成 snake_case;已经是 snake_case 的键原样通过。

在 Crawl 组件中,光做大小写转换还不够,v2 还对部分选项做了改名和语义合并,源码给出了明确的映射(firecrawl_crawl_api.py):

v1 参数 v2 参数 说明
maxDepth max_discovery_depth 改名
allowBackwardLinks crawl_entire_domain 改名
ignoreSitemap(bool) sitemap="skip" v2 移除了该布尔参数,改为 sitemap 模式枚举

Map 组件中同样的枚举化思想体现为 sitemap_only → sitemap="only"ignore_sitemap → sitemap="skip"。这套"默认值 + 重命名 + 枚举映射"的适配层,正是该 Bundle "built against the firecrawl-py v2 SDK" 的工程实质。

五、本地开发与验证

README 的 Develop 一节给出的开发流程是:

cd src/bundles/firecrawl
pip install -e .
lfx extension validate src/lfx_firecrawl

即先以 editable 方式安装 Bundle,再用 lfx extension validate 对扩展目录做校验。结合 pyproject.toml 的 hatch 打包配置可以知道:editable 安装时组件与 extension.json 都能被加载器发现(wheel 与 editable 双通道兜底),因此本地改动组件代码后重启服务器即可生效。

六、旧流程迁移:迁移表如何兜底存量 Flow

README 的 Migration 一节说明:引用了旧类名或旧导入路径 lfx.components.firecrawl.* 的已保存 Flow,会由迁移表自动改写为新的命名空间 ID。迁移表位于 migration_table.json,其中针对 Firecrawl 的条目覆盖了三类旧引用,例如 Crawl 组件(表内 L836-L851 一带):

  • 旧导入路径 lfx.components.firecrawl.firecrawl_crawl_api.FirecrawlCrawlApi → 目标 ext:firecrawl:FirecrawlCrawlApi@official
  • 包级旧导入路径 lfx.components.firecrawl.FirecrawlCrawlApi → 目标 ext:firecrawl:FirecrawlCrawlApi@official
  • 旧槽位 ext:firecrawl:FirecrawlCrawlApi@official-pre-a → 目标 ext:firecrawl:FirecrawlCrawlApi@official

Map、Scrape、Search 三个组件各有同构的三条映射(分别对应表内 L856-L871、L876-L891、L896-L911 一带)。这也解释了 Bundle 内部的一个"看似冗余"的设计:components/firecrawl/init.py 的 docstring 明确指出,它按名重导出四个组件类,是为了让迁移表中指向 lfx.components.firecrawl.<Class> 的旧条目仍然可以按名解析到移动后的组件类。对用户的实际影响是:升级后打开老 Flow,节点引用会被自动重写到 ext:firecrawl:*@official 新 ID,不需要手工改 JSON。

七、测试如何锁定 v2 行为

Bundle 自带单测 tests/test_firecrawl_components.py。测试策略值得注意:不访问网络、不要求真实安装 firecrawl-py,而是通过 sys.modules 注入伪造的 firecrawlfirecrawl.v2firecrawl.v2.types 模块(fixture mock_firecrawl),让组件方法内的惰性导入直接解析到 mock 客户端。关键断言包括:

  • Scrape:客户端以 api_key 构造、scrape 收到 URL 位置参数,返回的 model_dump() 结果原样进入 result.data;SDK 异常(如 RuntimeError)会向上透传;
  • Crawl:断言 kwargs 中出现 max_discovery_depth 且不含 max_depth、出现 crawl_entire_domain,直接锁死了第四节的 v1→v2 重命名逻辑;输出为 result.data["results"] 包裹的任务对象;
  • Map:sitemap_only=True 时断言 sitemap == "only"ignore_sitemap=True 时断言 sitemap == "skip";多 URL 的 links 被合并进 result.data["links"]
  • Search:query 为位置参数,limit/location 为关键字参数,SearchData 序列化结果直接输出。

这套测试与组件源码一一对应,也说明了该 Bundle 的行为契约(默认值、重命名、序列化格式)是被测试显式固化的。

八、小结

lfx-firecrawl 是 Langflow 扩展体系下"官方组件 → 独立 Bundle"演进的典型样本:

  • 分发与注册:pyproject.tomllangflow.extensions entry-point + extension.json 清单,pip install lfx-firecrawl 后重启即得 firecrawl 分组组件;
  • 能力面:Scrape(单页抓取,默认 Markdown + 仅主体内容)、Crawl(整站爬取,默认 2 层深度、1 万 URL 上限)、Map(多 URL 链接枚举,sitemap 枚举化)、Search(网络搜索,默认 5 条结果)四个组件,均以 JSON Data 输出,且关键入参支持 Agent 工具模式;
  • 工程细节:camelCase→snake_case 正则转换加上 maxDepth→max_discovery_depthallowBackwardLinks→crawl_entire_domain、sitemap 布尔开关→枚举模式的重命名适配层,是 firecrawl-py v2 兼容的核心;
  • 迁移保障:migration_table.json 将旧 lfx.components.firecrawl.* 引用自动重写到 ext:firecrawl:*@official,存量 Flow 无需手工修复。

如果你要在 Langflow 中搭建"网页数据 → Agent 上下文"的链路,这个 Bundle 提供的四个组件已经覆盖了从单页抓取到整站爬取、从站点结构枚举到联网搜索的完整入口,且行为都有对应单测约束,可以放心作为工作流的稳定数据源组件使用。

登录后查看全文
热门项目推荐
相关项目推荐