首页
/ Crawl4AI digest() 自适应爬取 API 详解:从查询驱动爬取、置信度停爬到状态断点续爬

Crawl4AI digest() 自适应爬取 API 详解:从查询驱动爬取、置信度停爬到状态断点续爬

2026-09-06 20:08:01作者:秋阔奎Evelyn

本文围绕 Crawl4AI 的 digest() 方法展开——它是 AdaptiveCrawler 面向"带查询的目标爬取"的主入口:给定起始 URL 和查询词,爬虫会自动评估信息是否已足够,无需人工指定爬取范围或停止时机。读完本文,你将掌握 digest() 的完整参数语义、CrawlState 返回结构的各字段含义、置信度/覆盖度/饱和度三指标的源码级计算方式,以及断点续爬、自动保存状态、进度监控等可直接复制运行的实战模式。

方法签名与定位

digest() 是自适应爬取(Adaptive Crawling)的核心接口。它从给定 URL 出发,在查询(query)引导下智能地遍历网站,并自动判断何时已收集到足够信息。在 adaptive_crawler.py 中,其真实签名为:

async def digest(
    start_url: str,
    query: str,
    resume_from: Optional[str] = None
) -> CrawlState

AdaptiveCrawlerAdaptiveConfigCrawlState 均已在 init.py 中作为顶层符号导出,因此可以直接 from crawl4ai import AsyncWebCrawler, AdaptiveCrawler, AdaptiveConfig, CrawlState 使用。

参数详解

start_url

  • 类型str
  • 必填:是
  • 说明:爬取起始 URL,应为可正常返回内容的 HTTP/HTTPS 地址,作为信息收集的入口。源码中 digest() 会先检查 start_url not in self.state.crawled_urls:若断点恢复时起始页已爬过,则直接跳过初始爬取,进入自适应扩展循环(见 digest 实现)。

query

  • 类型str
  • 必填:是
  • 说明:驱动整个爬取过程的查询语句,应包含你期望收集信息的关键词。它在底层至少承担三个角色:
    1. 链接预览打分digest() 内部通过 _crawl_with_preview() 构造 CrawlerRunConfig,把 query 传给 LinkPreviewConfig(query=query) 做 BM25 上下文化打分,并开启 score_links=True 进行内禀打分(见 _crawl_with_preview);
    2. 相关性评估StatisticalStrategy._calculate_relevance() 优先使用链接在抓取阶段算好的 contextual_score(BM25 分数),否则退化为 query 词与链接文本(链接文字 + title + meta title/description/keywords)的词集重叠率(见 相关性计算);
    3. 覆盖度评估:查询词被分词后,逐个统计其词频(tf)与文档频率(df),构成 Coverage 指标(见 覆盖度计算)。

因此 query 的质量直接决定爬取的走向——查询词越接近目标页面正文实际出现的术语,BM25 打分与覆盖度提升越快,爬取收敛得越早。

resume_from

  • 类型Optional[str]
  • 默认值None
  • 说明:先前保存的爬取状态文件路径。提供时,digest() 通过 CrawlState.load(resume_from) 从磁盘恢复完整状态(已爬 URL、知识库、待爬链接、词频统计、新增词历史等),并把本次传入的 query 覆盖写入状态(self.state.query = query),从而支持"先小范围试爬、中断后再扩爬"的工作流。状态文件的序列化格式是 JSON,由 CrawlState.save() 写出、CrawlState.load() 读回,其中 CrawlResult 会被转换为包含 url / content(raw markdown)/ links / metadata 的字典。

返回值:CrawlState 结构

digest() 返回一个 CrawlState 数据类实例,文档中列出的字段与源码完全对应:

字段 类型 含义
crawled_urls Set[str] 已成功爬取的全部 URL,用于去重
knowledge_base List[CrawlResult] 每页的爬取结果(含 markdown 正文与链接)
pending_links List[Link] 已发现但尚未爬取的内部链接
metrics Dict[str, float] 性能与质量指标,运行过程中持续写入 confidencecoverageconsistencysaturationpages_crawleddepth_reached
query str 原始查询

此外源码还维护了若干"用于打分的附加统计信息",这也是文档中 "Additional statistical information for scoring" 的具体所指:

  • term_frequencies / document_frequencies / documents_with_terms / total_documents:词频、文档频率等倒排统计,由 StatisticalStrategy.update_state() 在每页入库时增量更新;
  • new_terms_history:每爬一页新增了多少个"新词",是饱和度(递减收益)计算的原始序列;
  • crawl_order:页面爬取顺序,方便复盘爬虫实际走了哪条路径;
  • kb_embeddings / query_embeddings / expanded_queries / semantic_gaps 等:仅在 strategy="embedding" 时使用的语义空间状态。

工作原理:五步智能爬取算法

文档将 digest() 描述为五步智能爬取流程,与源码主循环一一对应:

# 主循环骨架(摘自 adaptive_crawler.py 的 digest())
if start_url not in self.state.crawled_urls:
    result = await self._crawl_with_preview(start_url, query)   # 1. 初始爬取
    ...
while depth < self.config.max_depth:
    confidence = await self.strategy.calculate_confidence(state) # 2/3. 计算置信度
    if await self.strategy.should_stop(state, self.config):     # 5. 停止判断
        break
    ranked_links = await self.strategy.rank_links(state, cfg)   # 4. 链接排序
    to_crawl = ranked_links[:self.config.top_k_links]           # 自适应选择 Top-K
    new_results = await self._crawl_batch(to_crawl, query)      # 并行抓取
    await self.strategy.update_state(state, new_results)
    depth += 1
  1. 初始爬取:先对 start_url 执行一次"带链接预览"的爬取。_crawl_with_preview() 内部使用 LinkPreviewConfig(include_internal=True, include_external=False, query=query, concurrency=5, timeout=link_preview_timeout, max_links=50),即只保留同域链接、用 query 做 BM25 打分,并过滤掉没有 head 元数据的死链接(见 async_configs.py 中的 LinkPreviewConfig)。
  2. 链接分析:所有新发现的同域内链进入 state.pending_links;排序时跳过已爬 URL,并对每个候选链接计算"相关性 + 新颖度 + 权威性"加权分。
  3. 三指标评分:默认统计策略(StatisticalStrategy)以固定权重 0.4*coverage + 0.3*consistency + 0.3*saturation 合成置信度:
    • Coverage(覆盖度):对每个查询词,取 df/总页数(有多少页含该词)乘以对数词频加成,再对全部查询词求平均并开平方,值域 0~1;
    • Consistency(一致性):对知识库中每两页做词集的 Jaccard 相似度并取平均——页面间高度重叠意味着话题聚焦、信息连贯(见 一致性计算);
    • Saturation(饱和度):用"最近一页新词数 / 初始新词数"的比值反推递减收益,saturation = 1 - recent_rate/initial_rate,新词发现速度越快趋近零,饱和度越高(见 饱和度计算)。
  4. 自适应选择rank_links()0.5*relevance + 0.3*novelty + 0.2*authority 加权(权重来自 AdaptiveConfig,默认值恰好如此),只取前 top_k_links 个且未爬过的链接,交由 _crawl_batch()asyncio.gather 并发抓取,失败的页面会被静默过滤、不中断流程(见 批量抓取)。
  5. 停止决策should_stop() 与主循环共同构成停止闸门,任何一条触发即退出(详见下文"停止条件")。

循环结束后,digest() 还会再算一次最终置信度写入 state.metrics['confidence'],并补充 pages_crawleddepth_reached 两项统计;若配置了 save_state=True 且给出 state_path,每个 depth 结束后都会落盘一次,结束时再做最终保存。

实战示例(可直接运行)

以下示例完整继承官方文档 digest.md 的四个场景,并补充了必要的导入说明。

基础用法

import asyncio
from crawl4ai import AsyncWebCrawler, AdaptiveCrawler

async def main():
    async with AsyncWebCrawler() as crawler:
        adaptive = AdaptiveCrawler(crawler)

        state = await adaptive.digest(
            start_url="https://docs.python.org/3/",
            query="async await context managers"
        )

        print(f"Crawled {len(state.crawled_urls)} pages")
        print(f"Confidence: {adaptive.confidence:.0%}")

asyncio.run(main())

带配置

AdaptiveConfig 的全部字段与默认值定义见 AdaptiveConfig。示例中用到的三项核心参数:

from crawl4ai import AsyncWebCrawler, AdaptiveCrawler, AdaptiveConfig

config = AdaptiveConfig(
    confidence_threshold=0.9,  # 置信度阈值,默认 0.7,要求更高把握
    max_pages=30,              # 最大爬取页数,默认 20
    top_k_links=3               # 每个 depth 跟随的最高分链接数,默认 3
)

async with AsyncWebCrawler() as crawler:
    adaptive = AdaptiveCrawler(crawler, config=config)

    state = await adaptive.digest(
        start_url="https://api.example.com/docs",
        query="authentication endpoints rate limits"
    )

常用配置参数速查(默认值均取自源码):

参数 默认值 作用
confidence_threshold 0.7 置信度达到该值即判定信息充分、停止爬取
max_depth 5 自适应扩展循环的最大轮数(每轮跟随一批链接)
max_pages 20 累计爬取页数硬上限
top_k_links 3 每轮选取评分最高的 K 个链接
min_gain_threshold 0.1 最高分链接的预期增益低于该值则停止
strategy "statistical" 置信度策略:statistical(默认,无 LLM)或 embedding
saturation_threshold 0.8 饱和度达到该值即停止
coverage_weight / consistency_weight / saturation_weight 0.4 / 0.3 / 0.3 三指标合成权重,构造后必须求和为 1(validate() 会断言)
relevance_weight / novelty_weight / authority_weight 0.5 / 0.3 / 0.2 链接排序权重,同样要求求和为 1
save_state / state_path False / None 开启后每轮 depth 自动把状态 JSON 落盘到 state_path
link_preview_timeout 5.0 链接 head 预览(BM25 打分)的超时秒数

注意:AdaptiveCrawler.__init__ 会对 config 调用 config.validate(),非法参数(如阈值越界、权重和不为 1)会在构造阶段直接抛断言错误,而不是爬取中途才暴露。

断点续爬(Resume)

# 第一次爬取——可能中途被中断
state1 = await adaptive.digest(
    start_url="https://example.com",
    query="machine learning algorithms"
)

# 手动保存状态(若配置了 save_state=True 则会自动保存)
state1.save("ml_crawl_state.json")

# 之后,从保存的状态恢复继续爬
state2 = await adaptive.digest(
    start_url="https://example.com",
    query="machine learning algorithms",
    resume_from="ml_crawl_state.json"
)

tests/adaptive/test_adaptive_crawler.py 中的 test_with_persistence 演示了另一种更完整的用法:第一次爬取用 AdaptiveConfig(..., save_state=True, state_path=state_path, max_pages=5) 做小规模试爬,随后把 config.max_pages 调大到 10,再以 resume_from=state_path 恢复续爬——即"先试跑、再扩爬"的典型工程模式。

进度监控

state = await adaptive.digest(
    start_url="https://docs.example.com",
    query="api reference"
)

# 监控进度
print(f"Pages crawled: {len(state.crawled_urls)}")
print(f"New terms discovered: {state.new_terms_history}")
print(f"Final confidence: {adaptive.confidence:.2%}")

# 查看详细统计(含每个查询词的 tf/df、三指标分解)
adaptive.print_stats(detailed=True)

print_stats(detailed=True) 在统计策略下会额外打印 Query Coverage 明细:逐个查询词展示"出现在 x/y 页、共出现 n 次",未命中的词会标记 not found,非常直观地暴露"哪些查询词没被覆盖到"(实现见 print_stats)。另外,adaptive.get_relevant_content(top_k=5) 可按得分返回知识库中最相关的 Top-K 页面,adaptive.export_knowledge_base("kb.jsonl") 可将知识库导出为 JSONL 供下游 RAG/LLM 使用(测试脚本中均有实际调用)。

查询词最佳实践

官方文档给出的三条建议,结合源码实现可以更精确地理解其原理:

  1. 要具体(Be Specific):使用会真实出现在目标内容中的描述性术语

    # Good
    query = "python async context managers implementation"
    
    # Too broad
    query = "python programming"
    

    原因:覆盖度是按查询词逐个计算的,过宽的查询词(如 "python")会在起始页即被覆盖,无法驱动爬虫继续深入;而 "context managers implementation" 这类词需要多页积累才能覆盖,才能引导爬取走向正确的子树。

  2. 包含关键术语(Include Key Terms):加入你预期会找到的技术名词

    query = "oauth2 jwt refresh tokens authorization"
    

    这些词同时喂给 BM25 链接打分与覆盖度统计,是链接排序的"燃料"。

  3. 组合多个相关概念(Multiple Concepts)

    query = "rest api pagination sorting filtering"
    

    多概念组合会让覆盖度必须跨页累积才能达到阈值,天然引导爬虫覆盖更全的子页面集合。

文档同时建议查询词长度在 3~8 个词 效果最佳——分词器(_tokenize)会剔除标点与长度 ≤2 的 token,3~8 词恰好能留下足够多的有效评估维度而不至于过于发散。

性能考量

  • 起始 URL 选择:选导航良好的页面(如文档索引页)。起始页的内链数量与质量直接决定第一轮候选池的规模;_crawl_with_preview 默认只预览前 50 个同域链接(max_links=50concurrency=5)。
  • 查询词长度:3~8 个词通常最佳(理由见上)。
  • 链接密度:导航清晰的站点爬取效率更高——pending_links 池子越大、打分区分度越高;链接稀疏的站点容易在 1~2 轮 depth 后因"无候选链接"提前结束。
  • 缓存:对同一域名的重复爬取可开启 Crawl4AI 的缓存机制(CrawlerRunConfig 层面的 cache 选项),避免重复抓取相同页面。

错误处理与自动保存

try:
    state = await adaptive.digest(
        start_url="https://example.com",
        query="search terms"
    )
except Exception as e:
    print(f"Crawl failed: {e}")
    # 若配置中 save_state=True,则状态已按 state_path 自动保存,
    # 可用 resume_from=state_path 恢复现场

从源码结构看,digest() 本身对单页失败相当宽容:_crawl_batch 使用 asyncio.gather(..., return_exceptions=True) 收集结果,异常的页面只打印日志并被过滤,不会向上抛错;真正可能抛出的异常来自配置校验(validate() 断言)与 CrawlState.load(状态文件损坏/缺失字段)。配合 save_state=True + state_path,即使进程被 kill,也能在下一个进程用 resume_from 继续,且恢复后会跳过已爬 URL、不重复消耗请求。

停止条件(源码级确认)

文档列出四条停止条件,源码中实际的停止闸门比这更完整。在 digest() 主循环与 StatisticalStrategy.should_stop() 中,任一条件触发即停止:

  1. 置信度阈值confidence >= confidence_threshold(默认 0.7);
  2. 页数上限len(crawled_urls) >= max_pages(默认 20);
  3. 收益递减:两个层面——饱和度 saturation >= saturation_threshold(默认 0.8),或最高分候选链接的增益 ranked_links[0][1] < min_gain_threshold(默认 0.1);
  4. 无可用链接pending_links 为空,或评分后的候选全部已爬过;
  5. 深度上限(源码额外保证):depth >= max_depth(默认 5),即无论指标如何,扩展循环最多跑 5 轮。

循环正常退出后,最终置信度、pages_crawleddepth_reached 都会写入 state.metrics,可通过 state.metrics.get("confidence")adaptive.confidence 属性读取,adaptive.is_sufficient 则直接给出"是否达到阈值"的布尔结论。

延伸阅读

  • AdaptiveCrawler 类参考:构造函数、confidence/coverage_stats/is_sufficient 属性与知识导入导出的完整说明
  • 自适应爬取指南:统计策略与 Embedding 策略的对比、strategy="embedding" 的完整配置
  • 配置选项章节:进阶参数与 LLM 嵌入配置
  • 基础爬取示例:仓库内可运行的官方测试脚本,覆盖基本爬取、持久化恢复、停止条件验证与爬取路径分析
登录后查看全文
热门项目推荐
相关项目推荐

项目优选

收起
kernelkernel
deepin linux kernel
C
33
18
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.14 K
2.75 K
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
857
1.35 K
docsdocs
暂无描述
Markdown
898
5.82 K
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
921
1.84 K
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
3.8 K
1.02 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
531
596
cann-learning-hubcann-learning-hub
CANN 学习中心仓,支持在线互动运行、边学边练,提供教程、示例与优化方案,一站式助力昇腾开发者快速上手。
Jupyter Notebook
1.02 K
519
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.36 K
1.46 K
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
548
391