AI爬虫黑科技 firecrawl本地部署
昨日trace还是博主的小甜甜, 急不可耐的使用它写了几个爬虫,今日看到Dify上部署智能体,使用firecrawl, 瞬间就把trace当做牛夫人。
在大模型的时代,企业知识库RAG系统如雨后春笋,而实时主学习的利器:AI爬虫,一键将网页内容转换为LLM-ready的数据。先搞搞:firecrawl。
一、Firecrawl 是什么
FireCrawl是一款创新的爬虫工具,它能够无需站点地图,抓取任何网站的所有可访问子页面。与传统爬虫工具相比,FireCrawl特别擅长处理使用JavaScript动态生成内容的网站,并且可以转换为LLM-ready的数据。
git官网:
此外,它还提供了一个易于使用的API,让开发者能够轻松实现内容的爬取和转换。
可以先通过FireCrawl 提供的playground来快速体验下。
最简单的情况下,只需要填一个URL就可以,firecrawl会抓取到相关的内容,还可以通过LLM来提取信息。使用firecrawl的在线服务是需要付费的,免费的只有500credit,所以接下来我们看下如何自己本地运行。
二、安装
2.1 单独安装
项目的介绍中说了,目前还在早期阶段,不建议自己部署,如果想要跑可以源码启动。首先需要准备本地的环境:
- 下载源码
使用git或下载压缩包
git clone https://github.com/mendableai/firecrawl.git
- 设置环境参数
在根目录中创建一个 .env,可以复制 apps/api/.env.example 中的模板
cd /firecrawl/apps/api
cp .env.example .env
#window
copy .env.example .env
默认不会设置身份验证或任何可选子服务(pdf 解析、JS 阻止支持、AI 功能)
# .env
# ===== Required ENVS ======
NUM_WORKERS_PER_QUEUE=8
PORT=3002
HOST=0.0.0.0
#for self-hosting using docker, use redis://redis:6379. For running locally, use redis://localhost:6379
REDIS_URL=redis://redis:6379
#for self-hosting using docker, use redis://redis:6379. For running locally, use redis://localhost:6379
REDIS_RATE_LIMIT_URL=redis://redis:6379
XXXX
安装依赖项
使用 pnpm 安装依赖项
# cd apps/api # 确保您位于正确的文件夹中
pnpm install # 确保您拥有 pnpm 版本 9+!
运行项目
您需要打开 3 个终端来运行服务。
- 终端 1 - 设置 redis
在项目中的任何位置运行命令
redis-server
博主局域网已安装redis, 配置/apps/api/.env中的redis,故不需执行启动redis
- 终端 2 - 设置工作程序
现在,导航到 apps/api/ 目录并运行:
pnpm run workers
如果您要使用 llm-extract 功能,您还应该导出 OPENAI_API_KEY=sk-______
这将启动负责处理抓取作业的工作程序。
- 终端 3 - 设置主服务器
为此,请导航到 apps/api/ 目录。如果您尚未安装 pnpm,可以在此处安装:https://pnpm.io/installation
接下来,使用以下命令运行您的服务器:
pnpm run start
测试
curl -X GET http://localhost:3002/test
测试下载
curl -X POST http://localhost:3002/v1/crawl \
-H 'Content-Type: application/json' \
-d '{
"url": "https://docs.firecrawl.dev"
}'
也可以访问 http://localhost:3002/admin/@/queues/ ,查看firecrawl的管理后台。
2.2 自托管
下载源码
使用git或下载压缩包
git clone https://github.com/mendableai/firecrawl.git
设置环境参数
在根目录中创建一个 .env,可以复制 apps/api/.env.example 中的模板
cd /firecrawl/apps/api
cp .env.example .env
默认不会设置身份验证或任何可选子服务(pdf 解析、JS 阻止支持、AI 功能)
# .env
# ===== Required ENVS ======
NUM_WORKERS_PER_QUEUE=8
PORT=3002
HOST=0.0.0.0
#for self-hosting using docker, use redis://redis:6379. For running locally, use redis://localhost:6379
REDIS_URL=redis://redis:6379
#for self-hosting using docker, use redis://redis:6379. For running locally, use redis://localhost:6379
REDIS_RATE_LIMIT_URL=redis://redis:6379
PLAYWRIGHT_MICROSERVICE_URL=http://playwright-service:3000/html
## To turn on DB authentication, you need to set up supabase.
USE_DB_AUTHENTICATION=false
# ===== Optional ENVS ======
# Supabase Setup (used to support DB authentication, advanced logging, etc.)
SUPABASE_ANON_TOKEN=
SUPABASE_URL=
SUPABASE_SERVICE_TOKEN=
# Other Optionals
# use if you've set up authentication and want to test with a real API key
TEST_API_KEY=
# set if you'd like to test the scraping rate limit
RATE_LIMIT_TEST_API_KEY_SCRAPE=
# set if you'd like to test the crawling rate limit
RATE_LIMIT_TEST_API_KEY_CRAWL=
# set if you'd like to use scraping Be to handle JS blocking
SCRAPING_BEE_API_KEY=
# add for LLM dependednt features (image alt generation, etc.)
OPENAI_API_KEY=
BULL_AUTH_KEY=@
# use if you're configuring basic logging with logtail
LOGTAIL_KEY=
# set if you have a llamaparse key you'd like to use to parse pdfs
LLAMAPARSE_API_KEY=
# set if you'd like to send slack server health status messages
SLACK_WEBHOOK_URL=
# set if you'd like to send posthog events like job logs
POSTHOG_API_KEY=
# set if you'd like to send posthog events like job logs
POSTHOG_HOST=
# set if you'd like to use the fire engine closed beta
FIRE_ENGINE_BETA_URL=
# Proxy Settings for Playwright (Alternative you can can use a proxy service like oxylabs, which rotates IPs for you on every request)
PROXY_SERVER=
PROXY_USERNAME=
PROXY_PASSWORD=
# set if you'd like to block media requests to save proxy bandwidth
BLOCK_MEDIA=
# Set this to the URL of your webhook when using the self-hosted version of FireCrawl
SELF_HOSTED_WEBHOOK_URL=
# Resend API Key for transactional emails
RESEND_API_KEY=
# LOGGING_LEVEL determines the verbosity of logs that the system will output.
# Available levels are:
# NONE - No logs will be output.
# ERROR - For logging error messages that indicate a failure in a specific operation.
# WARN - For logging potentially harmful situations that are not necessarily errors.
# INFO - For logging informational messages that highlight the progress of the application.
# DEBUG - For logging detailed information on the flow through the system, primarily used for debugging.
# TRACE - For logging more detailed information than the DEBUG level.
# Set LOGGING_LEVEL to one of the above options to control logging output.
LOGGING_LEVEL=INFO
一定要将USE_DB_AUTHENTICATION设置为false
构建并运行 Docker 容器:
docker compose build
docker compose up -d
这将运行 Firecrawl 的本地实例,可通过 http://localhost:3002 访问。
你应该能够在 http://localhost:3002/admin/@/queues 上看到 管理端Bull Queue Manager UI。
测试
curl -X POST http://localhost:3002/v1/crawl \
-H 'Content-Type: application/json' \
-d '{
"url": "https://docs.firecrawl.dev"
}'
3.3 其他
开启AI功能
docker-compose.yaml中有对OpenAI的配置
因此我们可以跟换为兼容OpenAI API的其他大模型。只需要在.env文件中添加这些设置即可
OPENAI_API_KEY=xxx
OPENAI_BASE_URL=xxx
MODEL_NAME=xxx
然后重启
docker compose down
docker compose up -d
三、Firecrawl高级配置选项
Firecrawl提供了多种参数来配置抓取过程,以满足不同场景的需求。以下是一些关键配置最佳实践:
(一)抓取选项(Scrape Options)
- 内容保存格式
Firecrawl 允许用户选择多种内容保存格式,其中 Markdown 是默认格式,还支持 HTML、Raw HTML(整个网页的简单复制粘贴)、Links(页面中的链接列表)和 Screenshot(页面截图,其值为临时链接,有效期为 24 小时)。例如,以下代码可以以多种格式抓取 Stripe API 文档的前 5 页:
# Crawl the first 5 pages of the stripe API documentation``
stripe_crawl_result = app.crawl_url(
url="https://docs.stripe.com/api",
params={
"limit": 5, # Only scrape the first 5 pages including the base-url
"scrapeOptions": {
"formats": ["markdown", "html", "links", "screenshot"]
}
}
)
- 控制抓取内容范围
通过onlyMainContent参数(默认禁用),可以排除导航、页眉和页脚等内容,仅抓取主要内容。例如:
stripe_crawl_result = app.crawl_url(
url="https://docs.stripe.com/api",
params={
"limit": 5,
"scrapeOptions": {
"formats": ["markdown", "html"],
"onlyMainContent": True,
},
},
)
同时,includeTags和excludeTags参数接受 HTML 标签、类和 ID 的白名单 / 黑名单列表,进一步精确控制抓取的元素。例如:
stripe_crawl_result = app.crawl_url(
url="https://docs.stripe.com/api",
params={
"limit": 5,
"scrapeOptions": {
"formats": ["markdown", "html"],
"includeTags": ["code", "#page-header"],
"excludeTags": ["h1", "h2", ".main-content"],
},
},
)
(二)URL 控制(URL Control)
- 指定 URL 模式
includePaths参数可用于指定要包含的特定 URL 路径,excludePaths参数用于排除不需要的内容路径。例如,在抓取 Stripe 文档网站时,可以只抓取/payments/*路径下的页面,并排除/terminal/*和/financial - connections/*部分
2. 处理链接关系
allowBackwardLinks参数用于控制是否允许爬取指向已访问页面的链接,allowExternalLinks参数用于管理外部链接的处理。例如:
# Example of URL control parameters
url_control_result = app.crawl_url(
url="https://docs.stripe.com/",
params={
# Only crawl pages under the /payments path
"includePaths": ["/payments/*"],
# Skip the terminal and financial-connections sections
"excludePaths": ["/terminal/*", "/financial-connections/*"],
# Allow crawling links that point to already visited pages
"allowBackwardLinks": False,
# Don't follow links to external domains
"allowExternalLinks": False,
"scrapeOptions": {
"formats": ["html"]
}
}
)
# Print the total number of pages crawled
print(f"Total pages crawled: {url_control_result['total']}")
此外,maxDepth参数可以限制爬取的深度,例如设置为 2 时,将只抓取初始页面及其直接链接的页面。
(三)性能与限制(Performance & Limits)
1、控制抓取范围
limit参数用于设置最大抓取页面数,这对于避免在抓取大型网站时消耗过多资源至关重要。例如,在抓取大型电商网站时,可以设置limit为 1000,以限制抓取的页面数量。
2、确保页面完全加载
对于包含动态内容(如 JavaScript 处理的内容)、iFrames 或大型媒体元素的网站,可以使用waitFor参数设置等待时间,让页面有足够时间加载。同时,timeout参数可以确保在页面加载时间过长时,爬虫能够继续执行而不被卡住。例如:
stripe_crawl_result = app.crawl_url(
url="https://docs.stripe.com/api",
params={
"limit": 5,
"scrapeOptions": {
"formats": ["markdown", "html"],
"waitFor": 1000, # wait for a second for pages to load
"timeout": 10000, # timeout after 10 seconds
},
},
)
五、Firecrawl 和 LangChain 集成构建 AI 驱动的 Web 爬虫
首先安装 LangChain 及其相关库:
`pip install langchain langchain_community langchain_anthropic langchain_openai`
导入 FireCrawlLoader 类并对其进行初始化(将 ANTHROPIC_API_KEY 和 OPENAI_API_KEY 作为变量添加到 .env 文件中):
from dotenv import load_dotenv
from langchain_community.document_loaders.firecrawl import FireCrawlLoader
load_dotenv()
loader = FireCrawlLoader(
url="https://python.langchain.com/docs/integrations/providers/",
mode="crawl",
params={"limit": 5, "scrapeOptions": {"onlyMainContent": True}},
)
开始爬取
`# Start the crawl``docs = loader.load()`
下一步进行切块(LLM在文本切块中的应用与实践)
from langchain_text_splitters import RecursiveCharacterTextSplitter
# Add text splitting before creating the vector store
text_splitter = RecursiveCharacterTextSplitter(chunk_size=1000, chunk_overlap=100)
# Split the documents
split_docs = text_splitter.split_documents(docs)
向量存储(构建非英文RAG(Retrieval-Augmented Generation)系统时,embedding很重要)
from langchain_chroma import Chroma
from langchain.embeddings import OpenAIEmbeddings
from langchain_community.vectorstores.utils import filter_complex_metadata
# Create embeddings for the documents
embeddings = OpenAIEmbeddings()
# Create a vector store from the loaded documents
docs = filter_complex_metadata(docs)
vector_store = Chroma.from_documents(docs, embeddings)
最后一步是使用 Claude 3.5 Sonnet 作为语言模型构建 QA 链:
from langchain.chains import RetrievalQA
from langchain_anthropic import ChatAnthropic
# Initialize the language model
llm = ChatAnthropic(model="claude-3-5-sonnet-20240620", streaming=True)
# Create a QA chain
qa_chain = RetrievalQA.from_chain_type(
llm=llm,
chain_type="stuff",
retriever=vector_store.as_retriever(),
)
现在,我们可以询问有关我们文件的问题:
# Example question
query = "What is the main topic of the website?"
answer = qa_chain.invoke(query)
print(answer)
{
'query': 'What is the main topic of the website?',
'result': """The main topic of the website is LangChain's integrations with Hugging Face.
The page provides an overview of various LangChain components that can be used with
Hugging Face models and services, including:
1. Chat models
2. LLMs (Language Models)
3. Embedding models
4. Document loaders
5. Tools
The page focuses on showing how to use different Hugging Face functionalities within
the LangChain framework, such as embedding models, language models, datasets, and
other tools."""
}
六、使用案例
部署好了之后,我们就来详细看下如何使用吧。
6.1 scrape 36单网页爬取
首先我们可以通过REST API的方式向firecrawl发送指令,我们首先可以使用 /scrape 这个API来抓取一下他们自己公司的网站,使用如以下curl命令:
curl -X POST http://localhost:3002/v1/scrape -H 'Content-Type: application/json' -d '{ "url": "https://36kr.com/information/contact/" }'
当然也可以通过各种API工具来发送,使用体验会更好一些。
3.2 crawl 整站爬取
除了单个网页的抓取,firecrawl还可以抓取多个页面,使用/crawl API ,您给出要抓取的基本 URL,所有可访问的子页面都将被抓取。
curl -X POST <https://api.firecrawl.dev/v0/crawl> \\` `-H 'Content-Type: application/json' \\` `-d '{` `"url": "<https://mendable.ai>",` `"pageOptions": {` `"onlyMainContent": true,` `"includeHtml": true,` `"screenshot": true,` `"waitFor": 5000` `},` `"crawlerOptions": {` `"includes": ["/blog/*", "/products/*"],` `"maxDepth": 3,` `"mode": "fast",` `}` `}'
在此示例中,爬虫将完成以下功能:
- 仅抓取与模式
/blog/*,/products/*
和匹配的 URL。 - 跳过与模式
/admin/* ,/login/*
和匹配的 URL。 - 返回每页的完整文档数据。
- 爬行至最大深度 3。
- 使用快速抓取模式。
- 最多抓取 1000 个页面。
/crawl 不会直接返回结果,发送命令后会返回对应任务的JobID,之后的任务是会在后台执行,可以在前面展示过的管理后台里查看任务的运行情况。
关于API的所有参数选项,可以到文档中查看。
结合大模型
首先 firecrawl 支持对抓取的内容进行大模型提取,利用大模型的能力,直接将抓取结果按预期进行格式化处理。如果想使用这个能力,首先要在.env里配置对应的API KEY。
我们在抓取的命令里,加入extractorOptions,参考如下:
"extractorOptions": {` `"mode": "llm-extraction",` `"extractionPrompt": "Based on the information on the page, extract the information from the schema. ",` `"extractionSchema": {` `"type": "object",` `"properties": {` `"company_mission": {` `"type": "string"` `},` `"supports_sso": {` `"type": "boolean"` `},` `"is_open_source": {` `"type": "boolean"` `},` `"is_in_yc": {` `"type": "boolean"` `}` `},` `"required": [` `"company_mission",` `"supports_sso",` `"is_open_source",` `"is_in_yc"` `]` `}` `}
这样再次执行后,可以看到结果的最后就会有提取的内容。
通过代码使用
除了这种方式以外,还可以通过代码的方式来使用firecrawl,目前支持
Python SDK
Node SDK
Langchain Integration 🦜🔗
Llama Index Integration 🦙
Langchain JS Integration 🦜🔗
使用代码的方式会有更多的灵活性,可以更加方便的和自己的程序集成起来。下面是一个简单的例子,我用node sdk为例,先要安装:
npm install @mendable/firecrawl-js
然后就可以在代码中使用了
const crawlUrl = ‘<https://example.com>’;const params = {` `crawlerOptions: {` `excludes: ['blog/'],` `includes: [], // leave empty for all pages` `limit: 1000,` `},` `pageOptions: {` `onlyMainContent: true` `}
};const waitUntilDone = true;
const timeout = 5;const crawlResult = await app.crawlUrl(` `crawlUrl,` `params,` `waitUntilDone,` `timeout
);
这里需要说的,默认情况下,官方的SDK中使用的是https://api.firecrawl.dev/ 的在线服务,如果你觉得没问题,那需要去网站上申请API key。
如果你想要使用自己本地启动的服务,那需要自己去修改一下SDK的实现,相关的代码在项目中都开了,大概在这里。
自己把相关内容修改一下,然后自己使用就可以了。
举个栗子
另外还有一些比较不错的玩法,比如使用 firecrawl 的 /search API来信息收集,之后快速转换成LLM-ready的数据。
首先 search的内容大概是这样的。
import FirecrawlApp from '@mendable/firecrawl-js';`` ``//这里的API key根据自己需要了``const app = new FirecrawlApp({ apiKey: 'YOUR_API_KEY' });``const params = {` `searchOptions: {` `limit: 5,` `},` `pageOptions: {` `fetchPageContent: false` `}` `};`` ``// Perform a search``const result = await app.search('What is firecrawl?');
会拿到类似这样一个结果。
剩下就不一步步实现了接下来就简单说下思路:
我们可以针对返回的结果,再对每一个URL使用 /scrape
配置参数用上之前的llm-extraction,就可以对每一个结果抓取数据并提炼内容
再把提炼的结果存下来,比如存到存到向量数据库中
接下来这就可以作为LLM的辅助信息来使用了
总结
整体来说firecrawl的可玩性确实非常高,在AI和大模型的时代,给爬虫这个传统工具提供了一个非常有意思的新发展思路。如果你也感兴趣,可以自己动手来玩一玩,还是很有意思的。