首页
/ Crawl4AI SDK 完整参考:从安装、双配置体系到结构化提取与并发爬取的端到端开发指南

Crawl4AI SDK 完整参考:从安装、双配置体系到结构化提取与并发爬取的端到端开发指南

2026-09-06 18:14:25作者:胡易黎Nicole

导读:本文基于仓库 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.pytests/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.pydownload_all_models 等函数)。

1.5 快速小结

  1. pip install crawl4ai 安装,随后执行 crawl4ai-setup
  2. 报错时用 crawl4ai-doctor 诊断;
  3. 用最简 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.pyCrawlerRunConfig.cache_mode 的构造默认值确实是 CacheMode.BYPASS,与这一说明一致;而 arun() 参数指南章节写到的 “ENABLED” 属文档历史不一致,建议生产代码里总是显式传入你想要的 cache_mode

2.2 输出两种 Markdown

result.markdownMarkdownGenerationResult(详见后文),常见的两个关注点是:

  • 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.pyMemoryAdaptiveDispatcher),会依据系统内存动态调节并发。


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())

实践建议与迁移注意

  1. BrowserConfig 承载全局浏览器环境参数;
  2. CrawlerRunConfig 承载每次爬取的语义(缓存、内容过滤、提取策略、等待条件);
  3. 避免把 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() 的差异:

  1. 多 URL:传入 URL 列表;返回列表或(开启流式时)异步生成器;
  2. 调度器dispatcher 可注入高级并发控制;缺省内部使用 MemoryAdaptiveDispatcher 之类默认调度器;
  3. 流式CrawlerRunConfig(stream=True) 时用 async for 边完成边处理;
  4. 并行与元信息:每条 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 与引用输出

MarkdownGenerationResultresult.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" 存放媒体条目,每项含 srcalt/titlescore(启发式相关度)、desc/description(周边文本)等;links 字典含 "internal"/"external" 两个键,每项含 hreftexttitlecontextdomain 等:

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_filesBrowserConfig(accept_downloads=True) + downloads_path 时的本地文件路径列表;
  • screenshotscreenshot=True 时的 Base64 字符串,可用 base64.b64decode 落盘;
  • pdfpdf=True 时的 PDF 字节;
  • mhtmlcapture_mhtml=True 时单文件保存整页资源(CSS/图片/脚本),适合离线归档;
  • metadata:页面元数据(title/author 等)。

并发信息 dispatch_result

arun_many() 配合 dispatcher 时,每个 CrawlResult 可能带 DispatchResulttask_idmemory_usage/peak_memory(MB)、start_time/end_timeerror_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、可选的 locationtimestamp
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 的灵活性来自三类配置:

  1. BrowserConfig:浏览器如何启动与表现(无头/有头、代理、UA);
  2. CrawlerRunConfig:每次爬取如何运行(缓存、提取、超时、JS、等待条件);
  3. 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 int1080/600 初始窗口尺寸,影响响应式布局渲染
proxy str(已废弃) 弃用,改用 proxy_config(内部自动转换)
proxy_config dict/ProxyConfigNone {"server": "...", "username": "...", "password": "..."}
use_persistent_context boolFalse True 使用持久化浏览器上下文(跨运行保留 cookie/会话),同时隐式启用 managed browser
user_data_dir strNone 存放用户数据(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 boolFalse 关闭部分后台特性换取性能
text_mode boolFalse 尽量禁用图片等重内容,提速文本爬取
use_managed_browser boolFalse 托管交互/CDP 场景;持久化上下文开启时通常自动置真
extra_args list[] 传给底层浏览器的附加 flag,如 ["--disable-extensions"]
enable_stealth boolFalse 用 playwright-stealth 修改指纹,抗基础反爬
avoid_ads boolFalse 在浏览器上下文层拦截常见广告/统计域名(GA、DoubleClick 等)
avoid_css boolFalse 拦截 .css/.less/.scss/.sass 加载,仅要文本时更快更省

BrowserConfig 源码位于 crawl4ai/async_configs.py;其中 avoid_ads/avoid_css/user_agent_mode/enable_stealthcrawl4ai/browser_manager.pycrawl4ai/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 ExtractionStrategyNone 结构化提取(CSS/XPath/LLM/Regex)
markdown_generator MarkdownGenerationStrategy(默认实例) 定制 Markdown 输出;可用 content_source 选择 HTML 输入源(cleaned_html/raw_html/fit_html
css_selector strNone 只保留页面匹配该选择器的区域,影响整个提取流程
target_elements List[str]None 多个目标选择器;只聚焦这些元素做 Markdown 与数据提取,但整页的链接/媒体仍处理
excluded_tags listNone 整块移除标签,如 ["script", "style"]
excluded_selector strNone 反向选区排除,如 "#ads, .tracker"
only_text boolFalse 尽量只保留纯文本
prettiify boolFalse 美化 HTML(慢,纯外观)
keep_data_attributes boolFalse 清洗时保留 data-* 属性
remove_forms boolFalse 移除全部 <form>

B) 缓存与会话

参数 类型/默认 作用
cache_mode CacheMode ENABLED/BYPASS/DISABLED/READ_ONLY/WRITE_ONLY;当前源码构造默认值为 CacheMode.BYPASS
session_id strNone 复用同一浏览器页签跨多次 arun()
bypass_cache boolFalse 等价 CacheMode.BYPASS
disable_cache boolFalse 等价 CacheMode.DISABLED
no_cache_read boolFalse 等价 WRITE_ONLY(只写不读)
no_cache_write boolFalse 等价 READ_ONLY(只读不写)

缓存机制的底层读写由 crawl4ai/cache_context.pyshould_read/should_write 判定)与 crawl4ai/async_database.py(SQLite 存储)支撑。

C) 页面导航与时机

参数 类型/默认 作用
wait_until strdomcontentloaded 导航完成条件,常取 networkidledomcontentloaded
page_timeout int(60000ms) 导航/JS 步骤超时
wait_for strNone "css:选择器""js:() => boolean" 条件等待
wait_for_images boolFalse 等待图片加载完成
delay_before_return_html float(0.1s) 捕获最终 HTML 前额外停顿
check_robots_txt boolFalse 抓取前检查并遵守 robots.txt(带 SQLite 缓存,实现见 crawl4ai/utils.pycan_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 boolFalse True 表示复用已有会话只跑 JS,不做整页重新导航
ignore_body_visibility bool(默认 True 跳过 <body> 可见性检查,通常保持 True
scan_full_page boolFalse 自动滚动加载追加式动态内容(传统无限滚动)
scroll_delay float(0.2s) 全页扫描/整页截图时的滚动间隔
process_iframes boolFalse 把 iframe 内容并入单页提取
flatten_shadow_dom boolFalse 把 Web Components 的 Shadow DOM 摊平进 light DOM,解决插槽/样式作用域/闭合根问题
remove_overlay_elements boolFalse 尝试移除遮挡主内容的弹窗/遮罩
remove_consent_popups boolFalse 处理 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 boolFalse 视口自适应内容高度

SPA 场景固定套路:后续调用保持 session_id + js_only=True

E) 媒体处理

参数 类型/默认 作用
screenshot boolFalse Base64 截图进 result.screenshot
screenshot_wait_for floatNone 截图前额外等待
screenshot_height_threshold int(约 20000) 页面超高时切换整页截图策略
pdf boolFalse result.pdf 返回 PDF 字节
capture_mhtml boolFalse 捕获含全部资源的 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 boolFalse 移除指向当前域外的全部链接
exclude_social_media_links boolFalse 剥离指向已知社交站的链接
exclude_domains list[] 自定义域名黑名单
exclude_internal_links boolFalse 反向排除站内链接(源码签名中存在)
preserve_https_for_internal_links boolFalse 被重定向到 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 可复用于 LLMExtractionStrategyLLMContentFilterJsonCssExtractionStrategy.generate_schemaJsonXPathExtractionStrategy.generate_schema(源码 crawl4ai/async_configs.pyLLMConfig.__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 结构与已知模式(如 navfooter)来系统修剪冗余:

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 会同时给出:

  1. raw_markdown:完整未过滤版本;
  2. fit_markdown:去除噪声后的精炼版;
  3. 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_htmlmedia/MediaItemlinks/Linkmetadata 结构)。


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

  1. on_browser_created——浏览器创建后;
  2. on_page_context_created——新的 context 与 page 创建后(登录/认证的最佳时机);
  3. before_goto——即将导航前;
  4. after_goto——导航完成后;
  5. on_user_agent_updated——用户代理变化时;
  6. on_execution_started——自定义 JS 开始执行时;
  7. before_retrieve_html——抓取最终 HTML 前;
  8. 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_startedjs_code 即将执行;
登录后查看全文
热门项目推荐
相关项目推荐