Crawl4AI SDK 完整参考:从安装、双配置体系到结构化提取与并发爬取的端到端开发指南
导读:本文基于仓库 docs/md_v2/complete-sdk-reference.md 这份面向 AI 助手与开发者的“超密集参考”(生成于 2025-10-19,对应 v0.7.4 时代的 API 形态)整理成文,并对照当前仓库源码(crawl4ai/version.py 标记为 0.9.0)逐一佐证。你将掌握 Crawl4AI 的完整使用链路:安装与自检、以 AsyncWebCrawler 为核心的生命周期管理、BrowserConfig/CrawlerRunConfig/LLMConfig 三层配置体系、Markdown 与 Fit 内容生成、CSS/XPath/正则/LLM 四类结构化提取、arun_many() 并发调度,以及 Session 与 Hooks 两类高级玩法——足以据此搭建可复现、可上生产的内容抓取管线。
说明:文末只读引用仓库文件供对照;文中涉及的功能参数默认值若与原文档存在出入(例如缓存模式),一律以当前仓库源码实现为准并单独标注。
1.1 基础安装
pip install crawl4ai
安装后需要执行一次环境初始化:
crawl4ai-setup
该命令会完成 OS 级别的检查(例如 Linux 下缺失的系统库)并确认环境可以开始爬取。仓库中对应的实现位于 crawl4ai/install.py,其中 install_playwright() 负责浏览器内核安装,doctor() / run_doctor() 提供诊断逻辑。
1.2 环境诊断
crawl4ai-doctor
crawl4ai-doctor 主要做三件事:
- 检查 Python 版本兼容性;
- 校验 Playwright 是否安装正确;
- 排查环境变量或库冲突。
如果诊断发现问题,按其建议修复(例如补充安装系统依赖包),随后重新运行 crawl4ai-setup。仓库测试 tests/cli/test_cli.py 与 tests/async/test_basic_crawling.py 覆盖了 CLI 与基础爬取的冒烟场景,可作为自检脚本参考。
1.3 验证安装:一个最小爬虫
import asyncio
from crawl4ai import AsyncWebCrawler, BrowserConfig, CrawlerRunConfig
async def main():
async with AsyncWebCrawler() as crawler:
result = await crawler.arun(
url="https://www.example.com",
)
print(result.markdown[:300]) # 打印提取文本的前 300 个字符
if __name__ == "__main__":
asyncio.run(main())
该脚本会启动一个无头浏览器会话加载 example.com,并返回约 300 字符的 Markdown。出错时重新运行 crawl4ai-doctor,或手动确认 Playwright 安装正确。
1.4 可选的高级安装
按需引入 Torch、Transformers 或全部依赖(主要用于本地语义过滤/聚类模型):
# 文本聚类(Torch)
pip install crawl4ai[torch]
crawl4ai-setup
# Transformers
pip install crawl4ai[transformer]
crawl4ai-setup
# 全部特性
pip install crawl4ai[all]
crawl4ai-setup
随后下载本地模型:
crawl4ai-download-models
对应实现见 crawl4ai/model_loader.py(download_all_models 等函数)。
1.5 快速小结
pip install crawl4ai安装,随后执行crawl4ai-setup;- 报错时用
crawl4ai-doctor诊断; - 用最简
AsyncWebCrawler+BrowserConfig/CrawlerRunConfig爬取example.com验证安装。
更多环境说明可参考 安装指南。
2.1 认识 Crawl4AI 的核心构件
Crawl4AI 面向 LLM 友好的网页抓取场景,核心 API 由四个构件组成:
AsyncWebCrawler:异步爬虫主体,负责驱动浏览器与整条抓取管线;BrowserConfig:控制浏览器“怎么启动与表现”(无头/有头、UA、代理、JS 开关等);CrawlerRunConfig:控制“每次爬取怎么运行”(缓存、提取、超时、JS、会话等);DefaultMarkdownGenerator:把 HTML 自动转为 Markdown,可挂接内容过滤器。
import asyncio
from crawl4ai import AsyncWebCrawler, BrowserConfig, CrawlerRunConfig, CacheMode
async def main():
browser_conf = BrowserConfig(headless=True) # 改 False 可观察浏览器运行
run_conf = CrawlerRunConfig(
cache_mode=CacheMode.BYPASS
)
async with AsyncWebCrawler(config=browser_conf) as crawler:
result = await crawler.arun(
url="https://example.com",
config=run_conf
)
print(result.markdown)
if __name__ == "__main__":
asyncio.run(main())
缓存模式的默认值提醒:快速上手章节强调“默认
CacheMode.BYPASS以便拿到新鲜内容;设置CacheMode.ENABLED开启缓存”。当前仓库源码 crawl4ai/async_configs.py 中CrawlerRunConfig.cache_mode的构造默认值确实是CacheMode.BYPASS,与这一说明一致;而arun()参数指南章节写到的 “ENABLED” 属文档历史不一致,建议生产代码里总是显式传入你想要的cache_mode。
2.2 输出两种 Markdown
result.markdown 是 MarkdownGenerationResult(详见后文),常见的两个关注点是:
result.markdown.raw_markdown:全量 HTML→Markdown;result.markdown.fit_markdown:经过内容过滤器(如PruningContentFilter)后的精炼版本。
from crawl4ai import AsyncWebCrawler, CrawlerRunConfig
from crawl4ai.content_filter_strategy import PruningContentFilter
from crawl4ai.markdown_generation_strategy import DefaultMarkdownGenerator
md_generator = DefaultMarkdownGenerator(
content_filter=PruningContentFilter(threshold=0.4, threshold_type="fixed")
)
config = CrawlerRunConfig(
cache_mode=CacheMode.BYPASS,
markdown_generator=md_generator
)
async with AsyncWebCrawler() as crawler:
result = await crawler.arun("https://news.ycombinator.com", config=config)
print("Raw Markdown length:", len(result.markdown.raw_markdown))
print("Fit Markdown length:", len(result.markdown.fit_markdown))
若不指定过滤器或 Markdown 生成器,通常只会得到 raw Markdown。PruningContentFilter 大约会增加 50ms 级处理耗时(具体取决于页面规模)。
2.3 免 LLM 的结构化提取(CSS 路线)
CSS 提取适合结构重复的列表页(商品、条目、文章卡片),零 AI 成本。Crawl4AI 还支持把原始 HTML 直接喂给爬虫:给 URL 加 raw:// 前缀即可。
import asyncio
import json
from crawl4ai import AsyncWebCrawler, CrawlerRunConfig, CacheMode
from crawl4ai import JsonCssExtractionStrategy
async def main():
schema = {
"name": "Example Items",
"baseSelector": "div.item",
"fields": [
{"name": "title", "selector": "h2", "type": "text"},
{"name": "link", "selector": "a", "type": "attribute", "attribute": "href"}
]
}
raw_html = "<div class='item'><h2>Item 1</h2><a href='https://example.com/item1'>Link 1</a></div>"
async with AsyncWebCrawler() as crawler:
result = await crawler.arun(
url="raw://" + raw_html,
config=CrawlerRunConfig(
cache_mode=CacheMode.BYPASS,
extraction_strategy=JsonCssExtractionStrategy(schema)
)
)
data = json.loads(result.extracted_content)
print(data)
if __name__ == "__main__":
asyncio.run(main())
要点:
- JSON 结果存放在
result.extracted_content; - 对“数据分布在兄弟节点上”的页面(如 Hacker News),可用
"source"键先跳到兄弟节点再取值:{"name": "score", "selector": "span.score", "type": "text", "source": "+ tr"}; - 把 HTML 前缀
raw://即可免网络请求直接测试。
还可以借助 LLM 一次性生成 schema:
from crawl4ai import JsonCssExtractionStrategy
from crawl4ai import LLMConfig
html = "<div class='product'><h2>Gaming Laptop</h2><span class='price'>$999.99</span></div>"
# OpenAI(需要 API token)
schema = JsonCssExtractionStrategy.generate_schema(
html,
llm_config=LLMConfig(provider="openai/gpt-4o", api_token="your-openai-token")
)
# 或 Ollama 开源模型(无需 token)
schema = JsonCssExtractionStrategy.generate_schema(
html,
llm_config=LLMConfig(provider="ollama/llama3.3", api_token=None)
)
strategy = JsonCssExtractionStrategy(schema)
2.4 LLM 提取(结构抽取快览)
import os
import json
import asyncio
from pydantic import BaseModel, Field
from crawl4ai import AsyncWebCrawler, CrawlerRunConfig, LLMConfig, LLMExtractionStrategy
class OpenAIModelFee(BaseModel):
model_name: str = Field(..., description="Name of the OpenAI model.")
input_fee: str = Field(..., description="Fee for input token for the OpenAI model.")
output_fee: str = Field(..., description="Fee for output token for the OpenAI model.")
async def extract_structured_data_using_llm(provider: str, api_token: str = None):
print(f"\n--- Extracting Structured Data with {provider} ---")
if api_token is None and provider != "ollama":
print(f"API token is required for {provider}. Skipping this example.")
return
extra_args = {"temperature": 0, "top_p": 0.9, "max_tokens": 2000}
crawler_config = CrawlerRunConfig(
cache_mode=CacheMode.BYPASS,
word_count_threshold=1,
page_timeout=80000,
extraction_strategy=LLMExtractionStrategy(
llm_config=LLMConfig(provider=provider, api_token=api_token),
schema=OpenAIModelFee.model_json_schema(),
extraction_type="schema",
instruction="From the crawled content, extract all mentioned model names along with their fees for input and output tokens.",
extra_args=extra_args,
),
)
async with AsyncWebCrawler() as crawler:
result = await crawler.arun(
url="https://openai.com/api/pricing/", config=crawler_config
)
print(result.extracted_content)
if __name__ == "__main__":
asyncio.run(
extract_structured_data_using_llm(provider="openai/gpt-4o", api_token=os.getenv("OPENAI_API_KEY"))
)
支持 OpenAI、Ollama 以及底层库所支持的任何 provider。
2.5 自适应爬取(Adaptive Crawling)
仓库中的 crawl4ai/adaptive_crawler.py 提供了面向“查询式知识收集”的 AdaptiveCrawler:围绕一个 query 自动决定爬哪些链接、何时停止:
import asyncio
from crawl4ai import AsyncWebCrawler, AdaptiveCrawler
async def adaptive_example():
async with AsyncWebCrawler() as crawler:
adaptive = AdaptiveCrawler(crawler)
result = await adaptive.digest(
start_url="https://docs.python.org/3/",
query="async context managers"
)
adaptive.print_stats()
print(f"Crawled {len(result.crawled_urls)} pages")
print(f"Achieved {adaptive.confidence:.0%} confidence")
if __name__ == "__main__":
asyncio.run(adaptive_example())
核心能力:信息足够时自动停止、只跟进相关链接、用置信度刻画信息完整度。更多内容见 自适应爬取文档。
2.6 多 URL 并发(预览)
import asyncio
from crawl4ai import AsyncWebCrawler, CrawlerRunConfig, CacheMode
async def quick_parallel_example():
urls = [
"https://example.com/page1",
"https://example.com/page2",
"https://example.com/page3"
]
run_conf = CrawlerRunConfig(cache_mode=CacheMode.BYPASS, stream=True)
async with AsyncWebCrawler() as crawler:
# 流式:结果完成一个处理一个
async for result in await crawler.arun_many(urls, config=run_conf):
if result.success:
print(f"[OK] {result.url}, length: {len(result.markdown.raw_markdown)}")
else:
print(f"[ERROR] {result.url} => {result.error_message}")
# 批模式:等全部完成
run_conf = run_conf.clone(stream=False)
results = await crawler.arun_many(urls, config=run_conf)
for res in results:
if res.success:
print(f"[OK] {res.url}, length: {len(res.markdown.raw_markdown)}")
if __name__ == "__main__":
asyncio.run(quick_parallel_example())
默认启用资源自适应调度器(仓库中对应 crawl4ai/async_dispatcher.py 的 MemoryAdaptiveDispatcher),会依据系统内存动态调节并发。
3.1 AsyncWebCrawler:构造与生命周期
AsyncWebCrawler 是异步爬取的核心类,正确用法是创建一次(可带 BrowserConfig 定制全局浏览器行为),然后多次调用 arun()(每次携带不同的 CrawlerRunConfig)。源码位于 crawl4ai/async_webcrawler.py(构造器 __init__ 约在 L115,start L176、close L188、arun L210、arun_many L973)。
class AsyncWebCrawler:
def __init__(
self,
crawler_strategy: Optional[AsyncCrawlerStrategy] = None,
config: Optional[BrowserConfig] = None,
always_bypass_cache: bool = False, # 已废弃
always_by_pass_cache: Optional[bool] = None, # 已废弃
base_directory: str = ...,
thread_safe: bool = False,
**kwargs,
):
...
参数说明:
crawler_strategy:高级用法,可注入自定义抓取策略;config:一个BrowserConfig对象;always_bypass_cache:已废弃,请改用CrawlerRunConfig.cache_mode;base_directory:存放缓存/日志的目录(当前默认取环境变量CRAWL4_AI_BASE_DIRECTORY或用户主目录,见源码构造签名);thread_safe:置True时启用部分并发安全措施,通常保持False。
典型初始化:
from crawl4ai import AsyncWebCrawler, BrowserConfig
browser_cfg = BrowserConfig(
browser_type="chromium",
headless=True,
verbose=True,
)
crawler = AsyncWebCrawler(config=browser_cfg)
生命周期:上下文管理器(推荐)
async with AsyncWebCrawler(config=browser_cfg) as crawler:
result = await crawler.arun("https://example.com")
# 离开 with 块时自动关闭浏览器等资源
手动 start / close
crawler = AsyncWebCrawler(config=browser_cfg)
await crawler.start()
result1 = await crawler.arun("https://example.com")
result2 = await crawler.arun("https://another.com")
await crawler.close()
适合长驻应用或需要精确掌控生命周期时使用。
3.2 arun():单页爬取主方法
async def arun(
url: str,
config: Optional[CrawlerRunConfig] = None,
# 兼容旧版本的遗留参数…
)
新式用法:把所有抓取语义塞进 CrawlerRunConfig——内容过滤、缓存、会话复用、JS 代码、截图等:
import asyncio
from crawl4ai import CrawlerRunConfig, CacheMode
run_cfg = CrawlerRunConfig(
cache_mode=CacheMode.BYPASS,
css_selector="main.article",
word_count_threshold=10,
screenshot=True,
)
async with AsyncWebCrawler(config=browser_cfg) as crawler:
result = await crawler.arun("https://example.com/news", config=run_cfg)
arun() 仍兼容直接传 css_selector=...、word_count_threshold=... 等旧式参数,但强烈建议迁移进 CrawlerRunConfig。
一个完整示例(Firefox + CSS 提取 + 等待条件):
import asyncio
import json
from crawl4ai import AsyncWebCrawler, BrowserConfig, CrawlerRunConfig, CacheMode
from crawl4ai import JsonCssExtractionStrategy
async def main():
browser_cfg = BrowserConfig(
browser_type="firefox",
headless=False,
verbose=True,
)
schema = {
"name": "Articles",
"baseSelector": "article.post",
"fields": [
{"name": "title", "selector": "h2", "type": "text"},
{"name": "url", "selector": "a", "type": "attribute", "attribute": "href"},
],
}
run_cfg = CrawlerRunConfig(
cache_mode=CacheMode.BYPASS,
extraction_strategy=JsonCssExtractionStrategy(schema),
word_count_threshold=15,
remove_overlay_elements=True,
wait_for="css:.post", # 等待文章出现
)
async with AsyncWebCrawler(config=browser_cfg) as crawler:
result = await crawler.arun(url="https://example.com/blog", config=run_cfg)
if result.success:
print("Cleaned HTML length:", len(result.cleaned_html))
if result.extracted_content:
articles = json.loads(result.extracted_content)
print("Extracted articles:", articles[:2])
else:
print("Error:", result.error_message)
asyncio.run(main())
实践建议与迁移注意
- 用
BrowserConfig承载全局浏览器环境参数; - 用
CrawlerRunConfig承载每次爬取的语义(缓存、内容过滤、提取策略、等待条件); - 避免把
css_selector/word_count_threshold等直接塞进arun(),统一收敛到 config 对象:run_cfg = CrawlerRunConfig(css_selector=".main-content", word_count_threshold=20) result = await crawler.arun(url="...", config=run_cfg)
3.3 arun_many():批量/并发爬取
async def arun_many(
urls: Union[List[str], List[Any]],
config: Optional[Union[CrawlerRunConfig, List[CrawlerRunConfig]]] = None,
dispatcher: Optional[BaseDispatcher] = None,
...
) -> Union[List[CrawlResult], AsyncGenerator[CrawlResult, None]]:
...
与 arun() 的差异:
- 多 URL:传入 URL 列表;返回列表或(开启流式时)异步生成器;
- 调度器:
dispatcher可注入高级并发控制;缺省内部使用MemoryAdaptiveDispatcher之类默认调度器; - 流式:
CrawlerRunConfig(stream=True)时用async for边完成边处理; - 并行与元信息:每条
CrawlResult可能附带dispatch_result(内存、起止时间等并发细节)。
批量示例
results = await crawler.arun_many(
urls=["https://site1.com", "https://site2.com"],
config=CrawlerRunConfig(stream=False) # 默认行为
)
for res in results:
if res.success:
print(res.url, "crawled OK!")
else:
print("Failed:", res.url, "-", res.error_message)
流式示例
config = CrawlerRunConfig(
stream=True, # 开启流式
cache_mode=CacheMode.BYPASS
)
async for result in await crawler.arun_many(
urls=["https://site1.com", "https://site2.com", "https://site3.com"],
config=config,
):
if result.success:
print(f"Just completed: {result.url}")
process_result(result)
自定义调度器
from crawl4ai import MemoryAdaptiveDispatcher # 亦可通过 crawl4ai.async_dispatcher 导入
dispatcher = MemoryAdaptiveDispatcher(
memory_threshold_percent=70.0,
max_session_permit=10,
)
results = await crawler.arun_many(
urls=["https://site1.com", "https://site2.com", "https://site3.com"],
config=my_run_config,
dispatcher=dispatcher,
)
URL 级差异化配置(url_matcher)
传入 config 列表,每个 config 可带 url_matcher;按顺序“先匹配先用”,务必把无 matcher 的默认 config 放在末尾兜底:
from crawl4ai import CrawlerRunConfig, MatchMode
from crawl4ai.processors.pdf import PDFContentScrapingStrategy
from crawl4ai.extraction_strategy import JsonCssExtractionStrategy
from crawl4ai.content_filter_strategy import PruningContentFilter
from crawl4ai.markdown_generation_strategy import DefaultMarkdownGenerator
# PDF —— 专用提取
pdf_config = CrawlerRunConfig(
url_matcher="*.pdf",
scraping_strategy=PDFContentScrapingStrategy(),
)
# 博客/文章页 —— 内容过滤
blog_config = CrawlerRunConfig(
url_matcher=["*/blog/*", "*/article/*", "*python.org*"],
markdown_generator=DefaultMarkdownGenerator(
content_filter=PruningContentFilter(threshold=0.48),
),
)
# 动态页面 —— JS 执行
github_config = CrawlerRunConfig(
url_matcher=lambda url: "github.com" in url,
js_code="window.scrollTo(0, 500);",
)
# API / JSON —— JSON 提取(可按需配 extraction_strategy)
api_config = CrawlerRunConfig(
url_matcher=lambda url: "api" in url or url.endswith(".json"),
)
# 兜底默认配置(无 url_matcher)
default_config = CrawlerRunConfig()
results = await crawler.arun_many(
urls=[
"https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf", # → pdf_config
"https://blog.python.org/", # → blog_config
"https://github.com/microsoft/playwright", # → github_config
"https://httpbin.org/json", # → api_config
"https://example.com/", # → default_config
],
config=[pdf_config, blog_config, github_config, api_config, default_config],
)
匹配类型:字符串 glob("*.pdf"、"*/blog/*")、函数(lambda url: ...)、混合列表配 MatchMode.OR/MatchMode.AND;按列表顺序首个命中者生效。若没有 config 命中且没有默认兜底,该 URL 会以 “No matching configuration found” 失败。
MemoryAdaptiveDispatcher 依据系统内存动态管理并发;SemaphoreDispatcher 则是固定并发上限的简化选择,二者实现均可对照 crawl4ai/async_dispatcher.py。完整并发讲解见 多 URL 爬取文档。
3.4 CrawlResult:一次爬取的全部产出
CrawlResult 封装单次爬取后返回的原始/加工内容、链接媒体明细与可选元数据(截图、PDF、提取的 JSON)。其 Pydantic 模型在 crawl4ai/models.py 中定义:
class CrawlResult(BaseModel):
url: str
html: str
success: bool
cleaned_html: Optional[str] = None
fit_html: Optional[str] = None # 为抽取优化过的预处理 HTML
media: Dict[str, List[Dict]] = {}
links: Dict[str, List[Dict]] = {}
downloaded_files: Optional[List[str]] = None
screenshot: Optional[str] = None
pdf: Optional[bytes] = None
mhtml: Optional[str] = None
markdown: Optional[Union[str, MarkdownGenerationResult]] = None
extracted_content: Optional[str] = None
metadata: Optional[dict] = None
error_message: Optional[str] = None
session_id: Optional[str] = None
response_headers: Optional[dict] = None
status_code: Optional[int] = None
ssl_certificate: Optional[SSLCertificate] = None
dispatch_result: Optional[DispatchResult] = None
基本信息字段
| 字段 | 含义 | 典型用法 |
|---|---|---|
url |
最终 URL(重定向后) | print(result.url) |
success |
管线是否无重大错误 | if not result.success: print(result.error_message) |
status_code |
HTTP 状态码(可能为 None) |
if result.status_code == 404: ... |
error_message |
失败文本描述 | 配合 success=False 读取 |
session_id |
复用的会话 ID | print("Session:", result.session_id) |
response_headers |
响应头字典 | result.response_headers.get("Server") |
ssl_certificate |
fetch_ssl_certificate=True 时的证书对象 |
result.ssl_certificate.issuer;支持导出 PEM/DER/JSON,见 SSL 证书文档 |
内容类字段
html:原始 HTML(可能很大);cleaned_html:清洗后的 HTML(按CrawlerRunConfig移除 script/style/被排除标签等)。
Markdown 与引用输出
MarkdownGenerationResult 是 result.markdown 的默认形态,含:
raw_markdown:完整 HTML→Markdown;markdown_with_citations:把链接改写为学术式引用[text][1]的版本;references_markdown:文末引用清单;fit_markdown/fit_html:仅当配置了内容过滤器(Pruning/BM25 等)时存在,否则为None。
if result.markdown:
md_res = result.markdown
print("Raw MD:", md_res.raw_markdown[:300])
print("Citations MD:", md_res.markdown_with_citations[:300])
print("References:", md_res.references_markdown)
if md_res.fit_markdown:
print("Pruned text:", md_res.fit_markdown[:300])
媒体与链接
media 字典按 "images"/"videos"/"audio" 存放媒体条目,每项含 src、alt/title、score(启发式相关度)、desc/description(周边文本)等;links 字典含 "internal"/"external" 两个键,每项含 href、text、title、context、domain 等:
for img in result.media.get("images", []):
if img.get("score", 0) > 5:
print("High-value image:", img["src"])
for link in result.links["internal"]:
print(f"Internal link to {link['href']} with text {link['text']}")
截图 / PDF / MHTML / 下载文件
extracted_content:启用extraction_strategy后的结构化 JSON 字符串;downloaded_files:BrowserConfig(accept_downloads=True)+downloads_path时的本地文件路径列表;screenshot:screenshot=True时的 Base64 字符串,可用base64.b64decode落盘;pdf:pdf=True时的 PDF 字节;mhtml:capture_mhtml=True时单文件保存整页资源(CSS/图片/脚本),适合离线归档;metadata:页面元数据(title/author等)。
并发信息 dispatch_result
arun_many() 配合 dispatcher 时,每个 CrawlResult 可能带 DispatchResult:task_id、memory_usage/peak_memory(MB)、start_time/end_time、error_message。
for result in results:
if result.success and result.dispatch_result:
dr = result.dispatch_result
print(f"URL: {result.url}, Task ID: {dr.task_id}")
print(f"Memory: {dr.memory_usage:.1f} MB (Peak: {dr.peak_memory:.1f} MB)")
print(f"Duration: {dr.end_time - dr.start_time}")
网络与控制台捕获
capture_network_requests=True / capture_console_messages=True 时额外提供:
network_requests:事件列表,event_type∈"request"/"response"/"request_failed",并带timestamp、URL、方法、状态、请求头等;console_messages:每条含type("log"/"error"/"warning"…)、text、可选的location、timestamp。
if result.network_requests:
requests = [r for r in result.network_requests if r.get("event_type") == "request"]
responses = [r for r in result.network_requests if r.get("event_type") == "response"]
print(f"Captured {len(requests)} requests, {len(responses)} responses")
if result.console_messages:
for msg in result.console_messages:
if msg.get("type") == "error":
print(f"Error: {msg.get('text')}")
版本迁移要点
markdown_v2:v0.5 已移除,访问会抛AttributeError,用markdown;fit_markdown/fit_html不再是CrawlResult顶层属性,请用result.markdown.fit_markdown/result.markdown.fit_html;- 完整字段速查见 CrawlResult 参考。
Crawl4AI 的灵活性来自三类配置:
BrowserConfig:浏览器如何启动与表现(无头/有头、代理、UA);CrawlerRunConfig:每次爬取如何运行(缓存、提取、超时、JS、等待条件);LLMConfig:LLM provider 的统一定制(模型、token、base_url、退避重试等)。
惯例是一个 BrowserConfig 服务整个爬虫会话,每次 arun() 传入新鲜或复用的 CrawlerRunConfig。
4.1 BrowserConfig 关键字段
class BrowserConfig:
def __init__(
browser_type="chromium",
headless=True,
proxy_config=None,
viewport_width=1080,
viewport_height=600,
verbose=True,
use_persistent_context=False,
user_data_dir=None,
cookies=None,
headers=None,
user_agent=None,
text_mode=False,
light_mode=False,
avoid_ads=False,
avoid_css=False,
extra_args=None,
enable_stealth=False,
# ……其余高级参数略
):
...
| 参数 | 类型/默认 | 作用 |
|---|---|---|
browser_type |
"chromium"/"firefox"/"webkit"(默认 chromium) |
底层浏览器引擎 |
headless |
bool(默认 True) |
False 便于可视化调试 |
viewport_width/viewport_height |
int(1080/600) |
初始窗口尺寸,影响响应式布局渲染 |
proxy |
str(已废弃) |
弃用,改用 proxy_config(内部自动转换) |
proxy_config |
dict/ProxyConfig(None) |
{"server": "...", "username": "...", "password": "..."} |
use_persistent_context |
bool(False) |
True 使用持久化浏览器上下文(跨运行保留 cookie/会话),同时隐式启用 managed browser |
user_data_dir |
str(None) |
存放用户数据(profile/cookie),持久会话需设置 |
ignore_https_errors |
bool(默认 True) |
容忍无效证书(开发/预发环境常见) |
java_script_enabled |
bool(默认 True) |
仅需静态内容时可关闭省开销 |
cookies |
list([]) |
预设 cookie,如 [{"name": "session", "value": "...", "url": "..."}] |
headers |
dict({}) |
每个请求附加的 HTTP 头 |
user_agent |
str(Chrome UA 默认值) |
自定义 UA;user_agent_mode="random" 可随机化,UA 生成逻辑见 crawl4ai/user_agent_generator.py |
light_mode |
bool(False) |
关闭部分后台特性换取性能 |
text_mode |
bool(False) |
尽量禁用图片等重内容,提速文本爬取 |
use_managed_browser |
bool(False) |
托管交互/CDP 场景;持久化上下文开启时通常自动置真 |
extra_args |
list([]) |
传给底层浏览器的附加 flag,如 ["--disable-extensions"] |
enable_stealth |
bool(False) |
用 playwright-stealth 修改指纹,抗基础反爬 |
avoid_ads |
bool(False) |
在浏览器上下文层拦截常见广告/统计域名(GA、DoubleClick 等) |
avoid_css |
bool(False) |
拦截 .css/.less/.scss/.sass 加载,仅要文本时更快更省 |
BrowserConfig 源码位于 crawl4ai/async_configs.py;其中 avoid_ads/avoid_css/user_agent_mode/enable_stealth 与 crawl4ai/browser_manager.py、crawl4ai/antibot_detector.py 的实现相互配合。文档对 enable_stealth 的说明是“默认 False,建议站点有反爬时开启”。
4.2 CrawlerRunConfig 关键字段
class CrawlerRunConfig:
def __init__(
word_count_threshold=200,
extraction_strategy=None,
markdown_generator=None,
cache_mode=None,
js_code=None,
wait_for=None,
screenshot=False,
pdf=False,
capture_mhtml=False,
locale=None, # e.g. "en-US", "fr-FR"
timezone_id=None, # e.g. "America/New_York"
geolocation=None, # GeolocationConfig 对象
enable_rate_limiting=False,
rate_limit_config=None,
memory_threshold_percent=70.0,
check_interval=1.0,
max_session_permit=20,
display_mode=None,
verbose=True,
stream=False,
# ……其余参数略
):
...
字段按功能分组说明(均可在 crawl4ai/async_configs.py 的构造函数中核实):
A) 内容处理
| 参数 | 类型/默认 | 作用 |
|---|---|---|
word_count_threshold |
int(约 200) |
丢弃字数低于阈值的文本块 |
extraction_strategy |
ExtractionStrategy(None) |
结构化提取(CSS/XPath/LLM/Regex) |
markdown_generator |
MarkdownGenerationStrategy(默认实例) |
定制 Markdown 输出;可用 content_source 选择 HTML 输入源(cleaned_html/raw_html/fit_html) |
css_selector |
str(None) |
只保留页面匹配该选择器的区域,影响整个提取流程 |
target_elements |
List[str](None) |
多个目标选择器;只聚焦这些元素做 Markdown 与数据提取,但整页的链接/媒体仍处理 |
excluded_tags |
list(None) |
整块移除标签,如 ["script", "style"] |
excluded_selector |
str(None) |
反向选区排除,如 "#ads, .tracker" |
only_text |
bool(False) |
尽量只保留纯文本 |
prettiify |
bool(False) |
美化 HTML(慢,纯外观) |
keep_data_attributes |
bool(False) |
清洗时保留 data-* 属性 |
remove_forms |
bool(False) |
移除全部 <form> |
B) 缓存与会话
| 参数 | 类型/默认 | 作用 |
|---|---|---|
cache_mode |
CacheMode |
ENABLED/BYPASS/DISABLED/READ_ONLY/WRITE_ONLY;当前源码构造默认值为 CacheMode.BYPASS |
session_id |
str(None) |
复用同一浏览器页签跨多次 arun() |
bypass_cache |
bool(False) |
等价 CacheMode.BYPASS |
disable_cache |
bool(False) |
等价 CacheMode.DISABLED |
no_cache_read |
bool(False) |
等价 WRITE_ONLY(只写不读) |
no_cache_write |
bool(False) |
等价 READ_ONLY(只读不写) |
缓存机制的底层读写由 crawl4ai/cache_context.py(should_read/should_write 判定)与 crawl4ai/async_database.py(SQLite 存储)支撑。
C) 页面导航与时机
| 参数 | 类型/默认 | 作用 |
|---|---|---|
wait_until |
str(domcontentloaded) |
导航完成条件,常取 networkidle 或 domcontentloaded |
page_timeout |
int(60000ms) |
导航/JS 步骤超时 |
wait_for |
str(None) |
"css:选择器" 或 "js:() => boolean" 条件等待 |
wait_for_images |
bool(False) |
等待图片加载完成 |
delay_before_return_html |
float(0.1s) |
捕获最终 HTML 前额外停顿 |
check_robots_txt |
bool(False) |
抓取前检查并遵守 robots.txt(带 SQLite 缓存,实现见 crawl4ai/utils.py 的 can_fetch) |
mean_delay/max_range |
float(0.1/0.3) |
arun_many() 请求间随机延时区间 |
semaphore_count |
int(5) |
arun_many() 最大并发 |
D) 页面交互
| 参数 | 类型/默认 | 作用 |
|---|---|---|
js_code |
str/list[str] |
页面加载后执行的 JS(点击/滚动/填表) |
js_code_before_wait |
str/list[str] |
在 wait_for 之前执行的 JS,用于先触发加载 |
js_only |
bool(False) |
True 表示复用已有会话只跑 JS,不做整页重新导航 |
ignore_body_visibility |
bool(默认 True) |
跳过 <body> 可见性检查,通常保持 True |
scan_full_page |
bool(False) |
自动滚动加载追加式动态内容(传统无限滚动) |
scroll_delay |
float(0.2s) |
全页扫描/整页截图时的滚动间隔 |
process_iframes |
bool(False) |
把 iframe 内容并入单页提取 |
flatten_shadow_dom |
bool(False) |
把 Web Components 的 Shadow DOM 摊平进 light DOM,解决插槽/样式作用域/闭合根问题 |
remove_overlay_elements |
bool(False) |
尝试移除遮挡主内容的弹窗/遮罩 |
remove_consent_popups |
bool(False) |
处理 GDPR/cookie 弹窗(OneTrust、Cookiebot、TrustArc 等 CMP),先点 “Accept All” 再回退 DOM 移除,见 crawl4ai/js_snippet/remove_consent_popups.js |
simulate_user / override_navigator / magic |
bool |
类人交互/伪造 navigator/自动处理弹窗(实验性) |
adjust_viewport_to_content |
bool(False) |
视口自适应内容高度 |
SPA 场景固定套路:后续调用保持 session_id + js_only=True。
E) 媒体处理
| 参数 | 类型/默认 | 作用 |
|---|---|---|
screenshot |
bool(False) |
Base64 截图进 result.screenshot |
screenshot_wait_for |
float(None) |
截图前额外等待 |
screenshot_height_threshold |
int(约 20000) |
页面超高时切换整页截图策略 |
pdf |
bool(False) |
result.pdf 返回 PDF 字节 |
capture_mhtml |
bool(False) |
捕获含全部资源的 MHTML 单文件快照 |
image_description_min_word_threshold |
int(约 50) |
图片 alt/描述视为有效的词数下限 |
image_score_threshold |
int(约 3) |
过滤低分图片(按尺寸/上下文启发式打分) |
exclude_external_images / exclude_all_images |
bool |
排除外域图片 / 排除全部图片 |
F) 链接与域名处理
| 参数 | 类型/默认 | 作用 |
|---|---|---|
exclude_social_media_domains |
list |
默认内置脸书/推特等域名清单,可扩展 |
exclude_external_links |
bool(False) |
移除指向当前域外的全部链接 |
exclude_social_media_links |
bool(False) |
剥离指向已知社交站的链接 |
exclude_domains |
list([]) |
自定义域名黑名单 |
exclude_internal_links |
bool(False) |
反向排除站内链接(源码签名中存在) |
preserve_https_for_internal_links |
bool(False) |
被重定向到 http 的内部链接仍保留 https,面向安全敏感抓取 |
默认社交域名清单:
[
'facebook.com', 'twitter.com', 'x.com', 'linkedin.com', 'instagram.com',
'pinterest.com', 'tiktok.com', 'snapchat.com', 'reddit.com',
]
G) 调试与日志
| 参数 | 作用 |
|---|---|
verbose |
逐步打印爬取过程日志 |
log_console |
记录页面 JS console 输出以便深度调试 |
H) 虚拟滚动(virtual_scroll_config)
虚拟滚动站点(Twitter/Instagram 这类内容“替换”而非“追加”的流)用 VirtualScrollConfig:
from crawl4ai import VirtualScrollConfig
virtual_config = VirtualScrollConfig(
container_selector="#timeline", # 可滚动容器 CSS 选择器
scroll_count=30, # 滚动次数
scroll_by="container_height", # "container_height"/"page_height"/像素(如500)
wait_after_scroll=0.5, # 每次滚动后等待秒数
)
config = CrawlerRunConfig(virtual_scroll_config=virtual_config)
选择指南:内容滚动时替换(Twitter/Instagram/虚拟表格)→ virtual_scroll_config;内容滚动时追加(传统无限滚动)→ scan_full_page。
I) URL 匹配(url_matcher / match_mode)
见 3.3 节的 config 列表场景。url_matcher=None 表示匹配所有 URL(也是默认兜底语义)。
clone():派生配置
两种 Config 都提供 clone(),便于不动原对象生成变体:
base_config = CrawlerRunConfig(
cache_mode=CacheMode.ENABLED,
word_count_threshold=200,
wait_until="networkidle",
)
stream_config = base_config.clone(stream=True, cache_mode=CacheMode.BYPASS)
debug_config = base_config.clone(page_timeout=120000, verbose=True)
4.3 LLMConfig:统一 LLM Provider 配置
LLMConfig 可复用于 LLMExtractionStrategy、LLMContentFilter、JsonCssExtractionStrategy.generate_schema 与 JsonXPathExtractionStrategy.generate_schema(源码 crawl4ai/async_configs.py 中 LLMConfig.__init__ 还额外接收 temperature/max_tokens/top_p/frequency_penalty/presence_penalty/stop/n 等可选采样参数)。
| 参数 | 说明 |
|---|---|
provider |
<厂商>/<模型> 标识,如 "openai/gpt-4o-mini"、"groq/llama3-70b-8192"、"anthropic/claude-3-5-sonnet-20240620"、"gemini/gemini-2.0-flash"、"deepseek/deepseek-chat"、"ollama/llama3"(默认 "openai/gpt-4o-mini") |
api_token |
三种给法:省略(按 provider 从环境变量读取,如 Gemini 读 GEMINI_API_KEY);直接传字符串;用 "env:XXX" 前缀引用环境变量 |
base_url |
自定义 API 端点 |
backoff_base_delay |
默认 2 秒,被限流后首次重试等待 |
backoff_max_attempts |
默认 3,同一提示词总尝试次数 |
backoff_exponential_factor |
默认 2,重试间隔增长因子(2s → 4s → 8s) |
llm_config = LLMConfig(
provider="openai/gpt-4o-mini",
api_token=os.getenv("OPENAI_API_KEY"),
backoff_base_delay=1,
backoff_max_attempts=5,
backoff_exponential_factor=3,
)
4.4 三配置合流的完整示例
import asyncio
from crawl4ai import (AsyncWebCrawler, BrowserConfig, CrawlerRunConfig,
CacheMode, LLMConfig, LLMContentFilter, DefaultMarkdownGenerator)
from crawl4ai import JsonCssExtractionStrategy
async def main():
# 1) 浏览器配置
browser_conf = BrowserConfig(headless=True, viewport_width=1280, viewport_height=720)
# 2) CSS 提取策略
schema = {
"name": "Articles",
"baseSelector": "div.article",
"fields": [
{"name": "title", "selector": "h2", "type": "text"},
{"name": "link", "selector": "a", "type": "attribute", "attribute": "href"},
],
}
extraction = JsonCssExtractionStrategy(schema)
# 3) LLM 内容过滤(Gemini,token 从环境变量 GEMINI_API_TOKEN 读取)
gemini_config = LLMConfig(
provider="gemini/gemini-1.5-pro",
api_token="env:GEMINI_API_TOKEN",
)
filter = LLMContentFilter(
llm_config=gemini_config,
instruction="""
Focus on extracting the core educational content.
Include: key concepts, important code examples, essential technical details.
Exclude: navigation elements, sidebars, footer content.
Format the output as clean markdown with proper code blocks and headers.
""",
chunk_token_threshold=500,
verbose=True,
)
md_generator = DefaultMarkdownGenerator(
content_filter=filter,
options={"ignore_links": True},
)
# 4) 运行配置
run_conf = CrawlerRunConfig(
markdown_generator=md_generator,
extraction_strategy=extraction,
cache_mode=CacheMode.BYPASS,
)
async with AsyncWebCrawler(config=browser_conf) as crawler:
result = await crawler.arun(url="https://example.com/news", config=run_conf)
if result.success:
print("Extracted content:", result.extracted_content)
else:
print("Error:", result.error_message)
if __name__ == "__main__":
asyncio.run(main())
完整参数表可查阅 参数参考文档。
5.1 DefaultMarkdownGenerator
import asyncio
from crawl4ai import AsyncWebCrawler, CrawlerRunConfig
from crawl4ai.markdown_generation_strategy import DefaultMarkdownGenerator
async def main():
config = CrawlerRunConfig(
markdown_generator=DefaultMarkdownGenerator()
)
async with AsyncWebCrawler() as crawler:
result = await crawler.arun("https://example.com", config=config)
if result.success:
print("Raw Markdown Output:\n")
print(result.markdown)
else:
print("Crawl failed:", result.error_message)
if __name__ == "__main__":
asyncio.run(main())
底层是 fork 自 html2text 并经修改的 HTML→文本引擎(仓库内位于 crawl4ai/html2text/),会保留标题、代码块、列表等结构,剥离 script/style 等无意义标签,并支持把链接转换为引用/引用清单。
options 常用项
md_generator = DefaultMarkdownGenerator(
options={
"ignore_links": True, # 移除全部超链接
"escape_html": False, # 是否转义 HTML 实体(默认常为 True)
"body_width": 80, # 每 N 字符折行;0/None 不折行
# 其他:ignore_images / skip_internal_links / include_sup_sub 等
}
)
content_source:选择 Markdown 的 HTML 输入源
raw_md_generator = DefaultMarkdownGenerator(content_source="raw_html") # 原始 HTML
cleaned_md_generator = DefaultMarkdownGenerator(content_source="cleaned_html") # 清洗后 HTML(默认)
fit_md_generator = DefaultMarkdownGenerator(content_source="fit_html") # 为抽取优化的 HTML
"cleaned_html"(默认):清洗/去噪后,多数场景推荐;"raw_html":保留全部原始内容(含导航、广告等);"fit_html":面向 schema 抽取做过简化的 HTML。
5.2 三种内容过滤器
BM25ContentFilter(按查询词聚焦)
from crawl4ai.markdown_generation_strategy import DefaultMarkdownGenerator
from crawl4ai.content_filter_strategy import BM25ContentFilter
bm25_filter = BM25ContentFilter(
user_query="machine learning",
bm25_threshold=1.2, # 越高保留越少、越相关;越低越宽松
language="english",
use_stemming=True, # 默认 True
)
md_generator = DefaultMarkdownGenerator(content_filter=bm25_filter)
user_query 留空时会尝试从页面元数据推断查询。
PruningContentFilter(无查询的通用“垃圾清除器”)
它综合分析文本密度、链接密度、HTML 结构与已知模式(如 nav、footer)来系统修剪冗余:
from crawl4ai.content_filter_strategy import PruningContentFilter
prune_filter = PruningContentFilter(
threshold=0.5, # 分数门槛(默认约 0.48)
threshold_type="fixed", # 或 "dynamic"
min_word_threshold=50, # 低于 N 词即丢弃
)
threshold_type="fixed":score >= threshold即保留;"dynamic"按标签类型、文本/链接密度自适应;- 链接密度高、纯
<div>包裹的区块会被惩罚降分。
LLMContentFilter(按自然语言指令过滤)
from crawl4ai import AsyncWebCrawler, CrawlerRunConfig, LLMConfig, DefaultMarkdownGenerator
from crawl4ai.content_filter_strategy import LLMContentFilter
filter = LLMContentFilter(
llm_config=LLMConfig(provider="openai/gpt-4o", api_token="your-api-token"),
instruction="""
Focus on extracting the core educational content.
Include: key concepts and explanations, important code examples.
Exclude: navigation elements, sidebars, footer content.
Format the output as clean markdown with proper code blocks and headers.
""",
chunk_token_threshold=4096, # 分块阈值
verbose=True,
)
config = CrawlerRunConfig(
markdown_generator=DefaultMarkdownGenerator(content_filter=filter, options={"ignore_links": True}),
)
性能提示:默认 chunk_token_threshold 接近无穷(整篇单块);调小(如 2048/4096)可启用并行分块处理。
指令技巧——精确保真(只删导航广告、原文措辞不动)或聚焦抽取(提取技术文档/代码/API 后重排为 Markdown):
# 1) 精确保真
filter = LLMContentFilter(
instruction="Extract the main educational content while preserving its original wording and substance completely. Remove only clearly irrelevant elements like navigation menus and ads.",
chunk_token_threshold=4096,
)
# 2) 聚焦重构
filter = LLMContentFilter(
instruction="Focus on extracting technical documentation, code examples, and API references. Reformat into clear, well-structured markdown.",
chunk_token_threshold=4096,
)
两遍组合:先 Pruning 去噪,再 BM25 按查询排序
无需二次网络请求——直接对 result.html 做本地过滤:
import asyncio
from crawl4ai import AsyncWebCrawler, CrawlerRunConfig
from crawl4ai.content_filter_strategy import PruningContentFilter, BM25ContentFilter
async def main():
config = CrawlerRunConfig()
async with AsyncWebCrawler() as crawler:
result = await crawler.arun("https://example.com/tech-article", config=config)
if not result.success or not result.html:
print("Crawl failed or no HTML content.")
return
raw_html = result.html
# 第一遍:修剪
pruning_filter = PruningContentFilter(threshold=0.5, min_word_threshold=50)
pruned_chunks = pruning_filter.filter_content(raw_html)
pruned_html = "\n".join(pruned_chunks)
# 第二遍:BM25 按查询排序
bm25_filter = BM25ContentFilter(user_query="machine learning", bm25_threshold=1.2)
bm25_chunks = bm25_filter.filter_content(pruned_html)
print("==== PRUNED OUTPUT (first pass) ====")
print(pruned_html[:500], "... (truncated)")
print("\n==== BM25 OUTPUT (second pass) ====")
print("\n---\n".join(bm25_chunks)[:500], "... (truncated)")
if __name__ == "__main__":
asyncio.run(main())
两种过滤器的抽象基类
RelevantContentFilter及实现均位于 crawl4ai/content_filter_strategy.py,可直接继承实现自定义过滤器(filter_content(html))。
5.3 “Fit” 输出与 MarkdownGenerationResult
使用过滤器后,result.markdown 会同时给出:
raw_markdown:完整未过滤版本;fit_markdown:去除噪声后的精炼版;fit_html:产出fit_markdown对应的 HTML 片段。
md_obj = result.markdown
print("RAW:\n", md_obj.raw_markdown)
print("CITED:\n", md_obj.markdown_with_citations)
print("REFERENCES:\n", md_obj.references_markdown)
print("FIT:\n", md_obj.fit_markdown)
工程建议:把 raw_markdown 喂给 LLM 做全文理解;把 fit_markdown 写入向量库降低 token 成本;references_markdown 保留链接溯源。相关专项文档见 Markdown 生成 与 Fit Markdown 教程。
5.4 内容选择与清理:Content Selection 全集
css_selector 与 target_elements 的区别
css_selector:把整条提取管线限定在匹配区域内;target_elements:Markdown 与结构化数据聚焦这些元素,但整页的链接/图片/表格仍完整采集:
config = CrawlerRunConfig(
target_elements=["article.main-content", "aside.sidebar"]
)
# result.markdown 聚焦目标元素;result.links 仍含整页链接
综合过滤
config = CrawlerRunConfig(
word_count_threshold=10, # 跳过过短文本块
excluded_tags=["nav", "footer", "header"], # 移除整标签
exclude_external_links=True, # 去掉外链
exclude_social_media_links=True, # 去掉社交链接
exclude_domains=["adtrackers.com", "spammynews.org"], # 域名黑名单
exclude_social_media_domains=["facebook.com", "twitter.com"],
exclude_external_images=True, # 外域图片
cache_mode=CacheMode.BYPASS,
)
iframe 与 Shadow DOM
# 内联 iframe + 移除遮罩
config = CrawlerRunConfig(process_iframes=True, remove_overlay_elements=True)
# Web Components 站点:摊平 Shadow DOM
config = CrawlerRunConfig(
flatten_shadow_dom=True,
wait_until="load",
delay_before_return_html=3.0, # 给组件水合留时间
)
执行顺序为:
js_code_before_wait → wait_for → delay → js_code → flatten_shadow_dom → page capture
仓库内 JS 注入脚本位于 crawl4ai/js_snippet/flatten_shadow_dom.js(resolve 插槽、剥离 shadow 作用域样式、强开闭合 shadow root),完整可运行示例见 docs/examples/shadow_dom_crawling.py。
抓取策略层(Scraping Strategies)
默认 HTML 处理由 LXMLWebScrapingStrategy 承担(LXML 实现,见 crawl4ai/content_scraping_strategy.py),大文档性能好、表检测稳健;WebScrapingStrategy 作为别名保留以兼容旧代码。PDF 场景可切换 crawl4ai/processors/pdf/ 的 PDFContentScrapingStrategy。亦可继承 ContentScrapingStrategy 自实现并返回 ScrapingResult(含 cleaned_html、media/MediaItem、links/Link、metadata 结构)。
6.1 JavaScript 执行
config = CrawlerRunConfig(
js_code="window.scrollTo(0, document.body.scrollHeight);"
)
# 或列表:先滚动再点击 “More”
js_commands = [
"window.scrollTo(0, document.body.scrollHeight);",
"document.querySelector('a.morelink')?.click();",
]
config = CrawlerRunConfig(js_code=js_commands)
6.2 等待条件
# CSS 等待
config = CrawlerRunConfig(wait_for="css:.athing:nth-child(30)")
# JS 等待:轮询直到返回 true 或超时
wait_condition = """() => {
const items = document.querySelectorAll('.athing');
return items.length > 50;
}"""
config = CrawlerRunConfig(wait_for=f"js:{wait_condition}")
6.3 动态分页:Hacker News “More”
复用同一 session_id,第二次起用 js_only=True 只跑 JS 不重新导航:
import asyncio
from crawl4ai import AsyncWebCrawler, CrawlerRunConfig
async def main():
config = CrawlerRunConfig(wait_for="css:.athing:nth-child(30)")
async with AsyncWebCrawler() as crawler:
result = await crawler.arun("https://news.ycombinator.com", config=config)
print("Initial items loaded.")
load_more_js = [
"window.scrollTo(0, document.body.scrollHeight);",
"document.querySelector('a.morelink')?.click();",
]
next_page_conf = CrawlerRunConfig(
js_code=load_more_js,
wait_for="""js:() => {
return document.querySelectorAll('.athing').length > 30;
}""",
js_only=True,
session_id="hn_session",
)
result2 = await crawler.arun("https://news.ycombinator.com", config=next_page_conf)
print("Items after load-more:", result2.cleaned_html.count("athing"))
if __name__ == "__main__":
asyncio.run(main())
表单交互也可用 js_code 完成(填值 + 提交 + 等待结果选择器)。
6.4 时序控制
config = CrawlerRunConfig(
page_timeout=60000, # 整页加载/脚本执行时间上限(ms)
delay_before_return_html=2.5, # 捕获最终 HTML 前等待(s)
# arun_many() 时:mean_delay 与 max_range 定义请求间随机延时
)
6.5 多步会话 + 提取合流
翻页同时挂上 JsonCssExtractionStrategy,翻到的新内容直接结构化:
config = CrawlerRunConfig(
session_id="ts_commits_session",
js_code=js_next_page,
wait_for=wait_for_more,
extraction_strategy=JsonCssExtractionStrategy(schema),
)
# 结束后清理会话:
await crawler.crawler_strategy.kill_session("ts_commits_session")
完整多页提交示例(连续翻页抓取 GitHub commit、判断“首个 commit 变化即新页加载”)见文档“Session Management”章节原文及 会话管理文档。虚拟滚动(VirtualScrollConfig)对比 JS 滚动见 4.2 节表格。
在 AsyncWebCrawler(更准确地说其 crawler_strategy)中,可通过 set_hook 注册以下钩子,注册实现位于 crawl4ai/async_crawler_strategy.py:
on_browser_created——浏览器创建后;on_page_context_created——新的 context 与 page 创建后(登录/认证的最佳时机);before_goto——即将导航前;after_goto——导航完成后;on_user_agent_updated——用户代理变化时;on_execution_started——自定义 JS 开始执行时;before_retrieve_html——抓取最终 HTML 前;before_return_html——HTML 即将返回给CrawlResult前。
重要告警:不要在
on_browser_created里做重活(此时还没有 page context,创建/关闭页面会打乱管线)。登录、加 cookie、配置路由拦截都应放在on_page_context_created。
import asyncio
from crawl4ai import AsyncWebCrawler, BrowserConfig, CrawlerRunConfig, CacheMode
from playwright.async_api import Page, BrowserContext
async def main():
crawler = AsyncWebCrawler(config=BrowserConfig(headless=True, verbose=True))
async def on_browser_created(browser, **kwargs):
print("[HOOK] on_browser_created")
return browser
async def on_page_context_created(page: Page, context: BrowserContext, **kwargs):
print("[HOOK] on_page_context_created")
# 示例 1:路由过滤——拦截图片请求
async def route_filter(route):
if route.request.resource_type == "image":
await route.abort()
else:
await route.continue_()
await context.route("**", route_filter)
# 示例 2(可选):在此模拟登录流程
# await page.goto("https://example.com/login")
# await page.fill("input[name='username']", "testuser")
# await page.fill("input[name='password']", "password123")
# await page.click("button[type='submit']")
# await page.wait_for_selector("#welcome")
await page.set_viewport_size({"width": 1080, "height": 600})
return page
async def before_goto(page, context, url, **kwargs):
print(f"[HOOK] before_goto - About to navigate: {url}")
await page.set_extra_http_headers({"Custom-Header": "my-value"})
return page
async def after_goto(page, context, url, response, **kwargs):
print(f"[HOOK] after_goto - Successfully loaded: {url}")
return page
async def before_return_html(page, context, html, **kwargs):
print(f"[HOOK] before_return_html - HTML length: {len(html)}")
return page
# 注册钩子
crawler.crawler_strategy.set_hook("on_browser_created", on_browser_created)
crawler.crawler_strategy.set_hook("on_page_context_created", on_page_context_created)
crawler.crawler_strategy.set_hook("before_goto", before_goto)
crawler.crawler_strategy.set_hook("after_goto", after_goto)
crawler.crawler_strategy.set_hook("before_return_html", before_return_html)
await crawler.start()
result = await crawler.arun(
"https://example.com",
config=CrawlerRunConfig(js_code="window.scrollTo(0, document.body.scrollHeight);",
wait_for="body", cache_mode=CacheMode.BYPASS),
)
print("Crawled URL:", result.url, "| HTML length:", len(result.html))
await crawler.close()
if __name__ == "__main__":
asyncio.run(main())
钩子生命周期小结
on_browser_created:浏览器已起、无页面无 context,仅做轻量设置;on_page_context_created:认证、路由拦截的理想位置;before_goto/after_goto:导航前后注入自定义头/日志/等待校验;on_user_agent_updated:UA 切换时生效;on_execution_started:js_code即将执行;
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0624
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00