首页
/ Crawl4AI CrawlResult 字段参考手册:从 HTML、Markdown 到网络事件的完整解析

Crawl4AI CrawlResult 字段参考手册:从 HTML、Markdown 到网络事件的完整解析

2026-09-06 14:52:44作者:虞亚竹Luna

本文以 Crawl4AI 官方文档 docs/md_v2/api/crawl-result.md 为主体,系统讲解 CrawlResult 结果对象的每一个字段:从基础爬取信息、原始/清洗 HTML、Markdown 生成结果、媒体与链接,到截图、PDF、MHTML 快照、网络请求与控制台消息捕获,并结合当前仓库源码(crawl4ai/models.pycrawl4ai/async_configs.pycrawl4ai/async_crawler_strategy.py)核实字段的真实定义、生成条件与底层实现。读完后你能够独立编写健壮的结果处理逻辑,正确读取 Crawl4AI 任意一次爬取返回的结构化数据,并将其送入数据管道或 AI 模型。

1. CrawlResult 是什么:单次爬取的完整"交付单"

CrawlResult 封装了单次爬取操作返回的一切内容:原始或处理后的页面内容、链接与媒体明细,以及可选的元数据(截图、PDF、提取的 JSON 等)。它是 AsyncWebCrawler.arun() / arun_many() 的核心返回值,也是 Crawl4AI 与下游数据管道之间的标准接口。

在源码中,CrawlResult 是一个 Pydantic BaseModel,定义于 crawl4ai/models.py(官方文档标注的位置为 crawl4ai/crawler/models.py,当前仓库中已位于 crawl4ai/models.py)。其核心字段声明如下:

class CrawlResult(BaseModel):
    url: str
    html: str
    fit_html: Optional[str] = None
    success: bool
    cleaned_html: Optional[str] = None
    media: Dict[str, List[Dict]] = {}
    links: Dict[str, List[Dict]] = {}
    downloaded_files: Optional[List[str]] = None
    js_execution_result: Optional[Dict[str, Any]] = None
    screenshot: Optional[str] = None
    pdf: Optional[bytes] = None
    mhtml: Optional[str] = None
    _markdown: Optional[MarkdownGenerationResult] = PrivateAttr(default=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
    redirected_url: Optional[str] = None
    redirected_status_code: Optional[int] = None
    network_requests: Optional[List[Dict[str, Any]]] = None
    console_messages: Optional[List[Dict[str, Any]]] = None
    tables: List[Dict] = Field(default_factory=list)
    # Cache validation metadata (Smart Cache)
    head_fingerprint: Optional[str] = None
    cached_at: Optional[float] = None
    cache_status: Optional[str] = None  # "hit", "hit_validated", "hit_fallback", "miss"
    # Anti-bot retry/proxy usage stats
    crawl_stats: Optional[Dict[str, Any]] = None

    model_config = ConfigDict(arbitrary_types_allowed=True)

注意一个源码级细节:markdown 并不是普通字段,而是一个由私有属性 _markdown 支撑的 property(见下文第 4 节)。所有可选项字段在对应功能未启用时保持 None,因此处理结果时应始终以"字段是否存在"作为判断入口。

1.1 字段与配置参数的对应关系速查

结果字段 由哪个配置控制 配置所在类
screenshot screenshot=True CrawlerRunConfig
pdf pdf=True CrawlerRunConfig
mhtml capture_mhtml=True CrawlerRunConfig
ssl_certificate fetch_ssl_certificate=True CrawlerRunConfig
network_requests capture_network_requests=True CrawlerRunConfig
console_messages capture_console_messages=True CrawlerRunConfig
downloaded_files accept_downloads=True + downloads_path BrowserConfig
extracted_content extraction_strategy=... CrawlerRunConfig
markdown.fit_markdown 内容过滤器(Pruning/BM25) MarkdownGenerationStrategy
dispatch_result arun_many(...) + 调度器 AsyncWebCrawler

上述开关均定义在 crawl4ai/async_configs.py 中,例如:

# CrawlerRunConfig.__init__ 中的相关参数(crawl4ai/async_configs.py)
screenshot: bool = False,
pdf: bool = False,
capture_mhtml: bool = False,
capture_network_requests: bool = False,
capture_console_messages: bool = False,
fetch_ssl_certificate: bool = False,

accept_downloads / downloads_path 属于浏览器层配置,定义在 BrowserConfigcrawl4ai/async_configs.py)。理解这一分层很重要:页面产物(截图、PDF、Markdown)由每次请求的 CrawlerRunConfig 控制;文件下载行为由一次性的 BrowserConfig 控制

2. 基础爬取信息字段

2.1 url(str)

最终爬取的 URL(经过重定向之后的地址)。

print(result.url)  # e.g., "https://example.com/"

2.2 success(bool)

爬取管道未发生重大错误时为 True,否则为 False。它应是所有结果处理逻辑的第一道判断:

if not result.success:
    print(f"Crawl failed: {result.error_message}")

2.3 status_code(Optional[int])

页面的 HTTP 状态码(如 200、404)。关键语义:若页面是通过重定向到达的,status_code 记录的是重定向链中第一个响应的状态码(例如 301 或 302)。

if result.status_code == 404:
    print("Page not found!")

2.4 redirected_status_code(Optional[int])

最终重定向目标的 HTTP 状态码。对于 302 → 200 的场景:status_code 是 302,redirected_status_code 是 200。对于非 HTTP 请求(raw: 原始 HTML、本地文件)该值为 None。配合源码中的 redirected_url 字段(crawl4ai/models.py)可以完整还原重定向链:

if result.status_code in (301, 302) and result.redirected_status_code == 200:
    print(f"Redirected to {result.redirected_url} (OK)")

这一对字段的区分对监控"301/302 流量"、识别失效链接、验证重定向策略都非常实用。

2.5 error_message(Optional[str])

success=False 时,包含失败的文字描述(超时、无效 URL、页面加载失败等)。

if not result.success:
    print("Error:", result.error_message)

2.6 session_id(Optional[str])

用于跨多次调用复用同一浏览器上下文的会话 ID。若你在 CrawlerRunConfig 中指定了 session_id="login_session",这里会原样返回,方便在批量任务中关联同一登录态:

print("Session:", result.session_id)

2.7 response_headers(Optional[dict])

最终 HTTP 响应头。可用于识别 WAF/CDN(Server 头)、验证响应类型、做反爬策略调试:

if result.response_headers:
    print("Server:", result.response_headers.get("Server", "Unknown"))

2.8 ssl_certificate(Optional[SSLCertificate])

CrawlerRunConfig 中设置 fetch_ssl_certificate=True 时,result.ssl_certificate 包含一个 SSLCertificate 对象,描述站点证书信息。该对象支持多种格式导出(PEM/DER/JSON),并可访问 issuersubjectvalid_fromvalid_until 等属性。SSLCertificate 类定义在 crawl4ai/ssl_certificate.py,更完整的用法见 SSL 证书文档

if result.ssl_certificate:
    print("Issuer:", result.ssl_certificate.issuer)

3. 原始与清洗后的内容

3.1 html(str)

原始、未经修改的最终页面 HTML。可能非常大,注意内存占用:

print(len(result.html))

3.2 cleaned_html(Optional[str])

按照 CrawlerRunConfig 配置清洗过的 HTML——脚本、样式或被排除的标签已被移除:

print(result.cleaned_html[:500])  # Show a snippet

3.3 fit_html(Optional[str])

从源码结构看(crawl4ai/models.py),fit_htmlCrawlResult 的顶层字段,同时 MarkdownGenerationResult 内部也持有一份(crawl4ai/models.py)。它对应"经过内容过滤(Pruning/BM25)后剩下的 HTML",是 fit_markdown 的 HTML 源头。

4. Markdown 字段与 MarkdownGenerationResult

Crawl4AI 支持 HTML → Markdown 转换,可选地包含三种形态:

  • Raw markdown(完整转换结果)
  • Links as citations:链接改写为学术风格引用,并附参考文献区
  • Fit markdown:当使用了内容过滤器(Pruning 或 BM25)时,过滤后的"贴合主题"文本

承载它们的模型是 MarkdownGenerationResult,源码定义见 crawl4ai/models.py

class MarkdownGenerationResult(BaseModel):
    raw_markdown: str                      # 完整 HTML→Markdown 转换结果
    markdown_with_citations: str           # 链接改写为学术引用
    references_markdown: str               # 文末的引用列表/脚注
    fit_markdown: Optional[str] = None     # 内容过滤(Pruning/BM25)后的文本
    fit_html: Optional[str] = None         # 生成 fit_markdown 的 HTML

fit_markdown / fit_html 只有在 MarkdownGenerationStrategy 中使用了内容过滤器(如 PruningContentFilterBM25ContentFilter)时才存在,否则保持 None

4.1 源码级实现:markdown 为什么"既是字符串又是对象"

这是 Crawl4AI 一个非常巧妙的兼容性设计,值得深入理解。result.markdown 的类型标注为 Optional[Union[str, MarkdownGenerationResult]],其背后实现(crawl4ai/models.py)分三层:

  1. 私有属性 _markdown:真正的存储位,类型为 MarkdownGenerationResult
  2. markdown property:返回一个 StringCompatibleMarkdown 对象;
  3. StringCompatibleMarkdownstr 的子类,内容取自 raw_markdown,同时通过 __getattr__ 转发属性访问到内部的 MarkdownGenerationResult
class StringCompatibleMarkdown(str):
    """A string subclass that also provides access to MarkdownGenerationResult attributes"""
    def __new__(cls, markdown_result):
        return super().__new__(cls, markdown_result.raw_markdown)

    def __init__(self, markdown_result):
        self._markdown_result = markdown_result

    def __getattr__(self, name):
        return getattr(self._markdown_result, name)

这带来一个实战能力:旧代码把 result.markdown 当字符串用(拼接、写文件)不会报错,新代码又能通过 result.markdown.fit_markdown 访问结构化字段。此外 model_dump() 被覆写(crawl4ai/models.py),确保序列化输出中始终包含 markdown 键,维持向后兼容。

# 同一个表达式,两种用法都成立:
text = result.markdown                        # 当字符串用(内容是 raw_markdown)
fit  = result.markdown.fit_markdown           # 当对象用(访问结构化字段)

4.2 读取 Markdown 各形态

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

如果启用了 DefaultMarkdownGenerator 的引用模式(options={"citations": True},生成器定义见 crawl4ai/markdown_generation_strategy.py),markdown_with_citationsreferences_markdown 中才会包含实质性的引用内容——这种"正文 + 编号引用 + 文末参考列表"的形式对 LLM 消费与学术式溯源非常友好。

5. 媒体与链接

5.1 media(Dict[str, List[Dict]])

包含发现的图片、视频、音频信息,键通常为 "images""videos""audios"。每个条目的常见字段:

  • src (str):媒体 URL
  • alttitle (str):描述文本
  • score (float):启发式判定的相关度评分
  • descdescription (Optional[str]):从周围文本提取的额外上下文
images = result.media.get("images", [])
for img in images:
    if img.get("score", 0) > 5:
        print("High-value image:", img["src"])

5.2 links(Dict[str, List[Dict]])

持有内链与外链数据,两个键:"internal""external"。从源码看(crawl4ai/utils.py),链接提取函数按目标域与当前页面域的关系把锚点分组,返回结构正是 {"internal": [...], "external": [...]}。每个条目的常见字段:

  • href (str):链接目标
  • text (str):链接文本
  • title (str):title 属性
  • context (str):周围文本片段
  • domain (str):外部链接的目标域名
for link in result.links["internal"]:
    print(f"Internal link to {link['href']} with text {link['text']}")

这一字段是深度爬取(DeepCrawlStrategy)与 URL 种子发现的数据来源之一。

6. 附加产物字段

6.1 extracted_content(Optional[str])

若使用了 extraction_strategy(CSS 选择器、LLM 结构化提取等),此处是结构化输出的 JSON 字符串:

import json
if result.extracted_content:
    data = json.loads(result.extracted_content)
    print(data)

6.2 downloaded_files(Optional[List[str]])

BrowserConfigaccept_downloads=True 且配置了 downloads_path 时,列出下载项的本地文件路径:

if result.downloaded_files:
    for file_path in result.downloaded_files:
        print("Downloaded:", file_path)

6.3 screenshot(Optional[str])

CrawlerRunConfigscreenshot=True 时的 Base64 编码截图:

import base64
if result.screenshot:
    with open("page.png", "wb") as f:
        f.write(base64.b64decode(result.screenshot))

6.4 pdf(Optional[bytes])

pdf=True 时的原始 PDF 字节流:

if result.pdf:
    with open("page.pdf", "wb") as f:
        f.write(result.pdf)

6.5 mhtml(Optional[str])

capture_mhtml=True 时的 MHTML 快照。MHTML(MIME HTML)格式把整页连同 CSS、图片、脚本等资源打包进单个文件,适合做离线归档与取证:

if result.mhtml:
    with open("page.mhtml", "w", encoding="utf-8") as f:
        f.write(result.mhtml)

6.6 metadata(Optional[dict])

页面级元数据(title、description、OG 数据等):

if result.metadata:
    print("Title:", result.metadata.get("title"))
    print("Author:", result.metadata.get("author"))

6.7 源码中的扩展字段(文档之外的补充)

从当前仓库源码结构看,CrawlResult 还带有一批官方参考文档未逐项展开的字段,实际使用时同样值得关注:

  • tables(List[Dict]):表格提取结果,形如 [{headers, rows, caption, summary}],由 table_extraction 策略或内置表格发现填充;
  • js_execution_result(Optional[Dict]):页面内 JS 求值/执行的结果回传;
  • head_fingerprint / cached_at / cache_status:智能缓存(Smart Cache)验证元数据,cache_status 取值为 "hit""hit_validated""hit_fallback""miss",可用于判断结果是否来自缓存及其验证状态;
  • crawl_stats:反爬重试与代理使用的统计信息(配合 max_retries / fallback_fetch_function 等参数);
  • redirected_url:与 redirected_status_code 配对,记录重定向最终地址。

7. dispatch_result:并发任务的资源画像

DispatchResult 提供并行爬取(如 arun_many() 配合自定义调度器)时的并发与资源占用信息,源码定义见 crawl4ai/models.py

  • task_id:并行任务的唯一标识
  • memory_usage (float):完成时刻的内存占用(MB)
  • peak_memory (float):任务执行期间记录的峰值内存(MB)
  • start_time / end_time (datetime):该爬取任务的时间范围
  • error_message (str):调度器或并发相关的错误
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}")

注意:该字段通常在使用 arun_many(...) 并搭配调度器(如 MemoryAdaptiveDispatcherSemaphoreDispatcher,实现见 crawl4ai/async_dispatcher.py)时才会被填充;不使用并发或调度器时保持 None

8. 网络请求与控制台消息捕获

CrawlerRunConfig 中启用 capture_network_requests=Truecapture_console_messages=True 后,CrawlResult 会包含两个诊断字段。捕获逻辑的实现位于 crawl4ai/async_crawler_strategy.py,通过监听页面的 request / response / requestfailed 事件完成。

8.1 network_requests(Optional[List[Dict[str, Any]]])

爬取期间捕获的所有网络请求、响应与失败事件的列表。结构要点:

  • 每个条目含 event_type 字段,取值为 "request""response""request_failed"
  • 请求事件包含 urlmethodheaderspost_dataresource_typeis_navigation_request
  • 响应事件包含 urlstatusstatus_textheadersrequest_timing
  • 失败事件包含 urlmethodresource_typefailure_text
  • 所有事件均含 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"]
    failures = [r for r in result.network_requests if r.get("event_type") == "request_failed"]

    print(f"Captured {len(requests)} requests, {len(responses)} responses, and {len(failures)} failures")

    # 分析 API 调用
    api_calls = [r for r in requests if "api" in r.get("url", "")]

    # 定位加载失败的资源
    for failure in failures:
        print(f"Failed to load: {failure.get('url')} - {failure.get('failure_text')}")

8.2 console_messages(Optional[List[Dict[str, Any]]])

爬取期间捕获的所有浏览器控制台消息列表:

  • 每个条目含 type 字段("log""error""warning" 等);
  • text 字段为实际消息文本;
  • 部分消息含 location 信息(URL、行号、列号);
  • 所有消息含 timestamp 字段。
if result.console_messages:
    message_types = {}
    for msg in result.console_messages:
        msg_type = msg.get("type", "unknown")
        message_types[msg_type] = message_types.get(msg_type, 0) + 1
    print(f"Message type counts: {message_types}")

    for msg in result.console_messages:
        if msg.get("type") == "error":
            print(f"Error: {msg.get('text')}")

这两个字段为页面网络活动与浏览器控制台提供了深度可见性,对调试 SPA 数据加载、安全分析以及理解复杂 Web 应用极为有价值。更多细节可参考 网络与控制台捕获文档

9. 完整示例:一次性访问所有字段

官方文档给出的 handle_result 是处理 CrawlResult 的标准模板:

async def handle_result(result: CrawlResult):
    if not result.success:
        print("Crawl error:", result.error_message)
        return

    # Basic info
    print("Crawled URL:", result.url)
    print("Status code:", result.status_code)

    # HTML
    print("Original HTML size:", len(result.html))
    print("Cleaned HTML size:", len(result.cleaned_html or ""))

    # Markdown output
    if result.markdown:
        print("Raw Markdown:", result.markdown.raw_markdown[:300])
        print("Citations Markdown:", result.markdown.markdown_with_citations[:300])
        if result.markdown.fit_markdown:
            print("Fit Markdown:", result.markdown.fit_markdown[:200])

    # Media & Links
    if "images" in result.media:
        print("Image count:", len(result.media["images"]))
    if "internal" in result.links:
        print("Internal link count:", len(result.links["internal"]))

    # Extraction strategy result
    if result.extracted_content:
        print("Structured data:", result.extracted_content)

    # Screenshot/PDF/MHTML
    if result.screenshot:
        print("Screenshot length:", len(result.screenshot))
    if result.pdf:
        print("PDF bytes length:", len(result.pdf))
    if result.mhtml:
        print("MHTML length:", len(result.mhtml))

    # Network and console capturing
    if result.network_requests:
        print(f"Network requests captured: {len(result.network_requests)}")
        req_types = {}
        for req in result.network_requests:
            if "resource_type" in req:
                req_types[req["resource_type"]] = req_types.get(req["resource_type"], 0) + 1
        print(f"Resource types: {req_types}")

    if result.console_messages:
        print(f"Console messages captured: {len(result.console_messages)}")
        msg_types = {}
        for msg in result.console_messages:
            msg_types[msg.get("type", "unknown")] = msg_types.get(msg.get("type", "unknown"), 0) + 1
        print(f"Message types: {msg_types}")

10. 关键要点、弃用字段与错误处理

  1. 已弃用的旧属性(访问即抛 AttributeError:源码中这些属性被显式实现为"报错并引导迁移"的 property(crawl4ai/models.py):
    • markdown_v2:v0.5 起移除,改用 result.markdown
    • 顶层 fit_markdown / fit_html:不再是顶层属性,改用 result.markdown.fit_markdownresult.markdown.fit_html
  2. Fit 内容的生成条件fit_markdown / fit_html 只有在 MarkdownGenerationStrategy 中使用内容过滤器(PruningContentFilterBM25ContentFilter)时才出现,未用过滤器时保持 None
  3. 引用与参考文献DefaultMarkdownGenerator 启用 options={"citations": True} 后,markdown_with_citationsreferences_markdown 才包含实质引用内容,便于 LLM 消费或学术式溯源。
  4. 链接与媒体分组links["internal"] / links["external"] 按域分组;media["images"] / ["videos"] / ["audios"] 存储媒体元素,可带评分与上下文。
  5. 错误情况success=False 时查 error_message(超时、无效 URL 等);若失败发生在 HTTP 响应之前,status_code 可能为 None
  6. 批量场景arun_many() 返回 CrawlResultContainercrawl4ai/models.py),可迭代地逐个消费 CrawlResult,每个结果均可独立应用上述所有字段。

CrawlResult 是 Crawl4AI 爬取产出的统一出口:配合合理的 BrowserConfigCrawlerRunConfig,一次爬取即可同时产出 HTML、多形态 Markdown、媒体/链接索引、结构化提取 JSON、截图/PDF/MHTML 快照、证书信息与网络诊断数据,并全部以结构化字段收敛于此。掌握其字段语义与生成条件,是编写可靠数据管道与 AI 输入层的前提。

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