news 2026/9/7 7:25:07

Crawl4AI 0.4.0 版本解析:PruningContentFilter 无监督内容过滤与 User-Agent 生成器实战

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Crawl4AI 0.4.0 版本解析:PruningContentFilter 无监督内容过滤与 User-Agent 生成器实战

Crawl4AI 0.4.0 版本解析:PruningContentFilter 无监督内容过滤与 User-Agent 生成器实战

【免费下载链接】crawl4ai🚀🤖 Crawl4AI: Open-source LLM Friendly Web Crawler & Scraper. Don't be shy, join here: https://discord.gg/jP8KfhDhyN项目地址: https://gitcode.com/GitHub_Trending/craw/crawl4ai

Crawl4AI 0.4.0(2024 年 12 月 1 日发布)是内容抽取能力的一次重要升级:它引入了基于 HTML 节点评分的无监督过滤策略PruningContentFilter,增强了面向查询的有监督过滤器BM25ContentFilter,并新增了可定制、可随机的 User-Agent 生成器。读完本文,你可以掌握两种内容过滤器的适用场景与参数配置、PruningContentFilter的评分剪枝原理,以及通过BrowserConfiguser_agent_mode实现请求指纹多样化的方法。

一、0.4.0 版本总览

根据 0.4.0 发布说明,该版本的关键亮点包括:

  1. PruningContentFilter:新增的无监督内容过滤策略,基于文本密度、链接密度等指标对 HTML 节点进行评分和剪枝,自动保留页面中最有价值的内容部分;
  2. User-Agent 生成器:新增 User-Agent 生成工具,解决兼容性问题,支持可定制的 UA 字符串,默认对每个请求随机化 UA 以增加多样性;
  3. 线程安全增强:为多线程/多协程并行处理环境增加了更完善的线程锁机制,保证多任务运行的一致性和稳定性;
  4. 过滤策略矩阵完善:用户可同时使用PruningContentFilter(无监督抽取)和BM25ContentFilter(基于用户查询的有监督过滤),且BM25ContentFilter增强了处理页面标题、meta 标签和描述的能力,使文本块分类与聚类更有效;
  5. 文档与测试同步更新:示例和教程更新以推广两种过滤器的配合使用,并新增PruningContentFilter单元测试、扩展BM25ContentFilter的边界用例覆盖。

发布说明同时指出:PruningContentFilter在当时仍处于实验性开发阶段,欢迎用户反馈以继续完善。

需要说明的是,当前仓库版本为 0.9.0(见 crawl4ai/version.py),以下所有实现细节均基于当前代码库核实,0.4.0 引入的核心类在当前版本中依然可用。

二、内容过滤架构:RelevantContentFilter 基类

在 crawl4ai/content_filter_strategy.py 中,三种过滤策略共享同一个抽象基类RelevantContentFilter,它定义了页面过滤的公共基础:

保留与排除标签集(基类__init__,第 50-111 行):

  • included_tagsarticlemainsectiondiv、列表结构(ul/ol/li)、文本内容(p/span/blockquote/pre/code)、标题(h1-h6)、表格、语义元素(figuredetails)等;
  • excluded_tagsnavfooterheaderasidescriptstyleformiframenoscript——这些标签会被直接剔除;
  • negative_patterns:正则nav|footer|header|sidebar|ads|comment|promo|advert|social|share,用于识别 class 或 id 中带有这些语义的容器(如class="sidebar"id="comments")。

查询回退机制extract_page_query(第 125-159 行):如果调用方未提供user_query,过滤器会按顺序回退——先取<title>,再取第一个<h1>文本,然后读取meta[name=keywords]meta[name=description];若仍为空,则取正文中第一个超过 50 字符的<p>段落的前 150 字符。这个机制正是 0.4.0 中"增强 BM25 对页面标题、meta 标签和描述的处理"的具体落地。

文本块提取extract_text_chunks(第 161-271 行):采用基于deque的手写深度优先遍历,将行内标签(aspanem等)视为不切断文本流的节点,遇到块级元素边界时把累积文本刷成一个(序号, 文本, header/content 类型, 元素)四元组,并可按min_word_threshold过滤过短的块。

这套"提取 → 评分 → 过滤 → 清洗"的流水线是理解两个核心过滤器的共同前提。

三、PruningContentFilter:无监督评分剪枝

PruningContentFilter(crawl4ai/content_filter_strategy.py)不需要任何用户查询,适合"我只想要正文,不需要搜索意图"的场景。其构造函数参数如下:

参数类型默认值说明
user_querystrNone保留参数(该过滤器不依赖查询)
min_word_thresholdintNone节点文本单词数低于该值时强制剪除(构造内提前返回分数 -1.0)
threshold_typestr"fixed"阈值类型:fixed固定阈值 /dynamic动态阈值
thresholdfloat0.48固定阈值或动态阈值的基础值

3.1 五维复合评分

_compute_composite_score(第 737-772 行)对每个节点计算加权复合分数,五个指标及权重(metric_weights)为:

  • text_density(权重 0.4)文本长度 / 标签总长度encode_contents得到的 HTML 串长度)。文本占比越高,说明节点内容密度越大;
  • link_density(权重 0.2)1 - 直接子级 <a> 链接文本长度 / 节点文本长度。链接占比越低的节点得分越高,专门压制导航、链接堆砌区;
  • tag_weight(权重 0.2):标签语义权重表tag_weights(第 617-632 行),如article: 1.5h1: 1.2p: 1.0div: 0.5span: 0.3
  • class_id_weight(权重 0.1)_compute_class_id_weight(第 774-785 行)检查节点的 class 和 id,若命中negative_patterns(sidebar、ads、comments 等)则扣 0.5 分(最低截断为 0);
  • text_length(权重 0.1)log(文本长度 + 1),对长文做对数平滑,避免超长节点主导评分。

最终分数为各启用指标的加权和除以权重之和,归一化到与阈值可直接比较的量纲。若设置了min_word_threshold且节点词数不足,直接返回 -1.0 保证被移除。

3.2 fixed 与 dynamic 两种阈值模式

_prune_tree(第 685-735 行)从<body>开始递归剪枝:

  • fixed 模式score < threshold(默认 0.48)即node.decompose()整个子树移除;
  • dynamic 模式:在基础阈值上做三次微调——语义重要标签(tag_importance表中article: 1.5h1: 1.4等,权重 > 1)阈值乘以 0.8(更宽容);文本占比text_ratio > 0.4再乘以 0.9;链接占比link_ratio > 0.6则乘以 1.2(更严格)。也就是说,重要标签更难被剪、纯文本节点更被保留、链接密集区更容易被剪。

节点不达标时整棵子树被decompose(),达标则递归处理子节点;最终返回<body>下所有含文本的顶层子元素 HTML 串列表。过滤前先执行_remove_comments_remove_unwanted_tags(按excluded_tags拆解nav/footer/script等)。

3.3 单元测试覆盖

tests/async/test_content_filter_prune.py 对该过滤器做了系统性验证:

  • test_basic_pruningmin_word_threshold=5下,高质量长段落保留,class="sidebar"class="social-share"的内容被剪除;
  • test_min_word_threshold:短摘要与短评论被过滤,长段落保留;
  • test_threshold_types:fixed 与 dynamic 模式对同一 HTML 产出不同结果集;
  • test_link_density_impactdynamic模式下,含 4 个链接的<div class="links">区块被压制,链接密集区被剪枝;
  • test_threshold_levels:参数化验证阈值单调性——阈值 0.3 时最多保留 4 个块,0.48(默认)时 2 个,0.7 时 1 个,可用于按页面噪声程度调参;
  • 还包含空输入、畸形 HTML(未闭合标签)、性能(< 0.1 秒)与输出一致性(多次运行结果相同)用例。

四、BM25ContentFilter:查询驱动的有监督过滤

BM25ContentFilter(crawl4ai/content_filter_strategy.py)与无监督的剪枝策略互补:它把"用户查询"当作相关性信号。构造参数:

参数类型默认值说明
user_querystrNone查询词;缺省时走extract_page_query回退链(title → h1 → meta → 首段)
bm25_thresholdfloat1.0加权后 BM25 分数低于该值的块被丢弃
languagestr"english"snowballstemmer 词干提取语言
use_stemmingboolTrue是否对语料与查询做词干提取

核心流程(filter_content,第 440-538 行):

  1. 用 lxml 解析 HTML,缺失<body>时自动包裹;
  2. 提取查询(user_query优先,否则页面元数据回退);
  3. 复用基类的extract_text_chunks得到有序文本块;
  4. 分词 → 词干提取 →clean_tokens去停用词,构建rank_bm25.BM25Okapi并计算每个块的分数;
  5. 标签权重调整(第 425-437 行priority_tags):h1: 5.0title: 4.0h2: 4.0h3: 3.0strong/blockquote/code: 2.0b/em/pre/th: 1.5,即adjusted_score = score * tag_weight,让标题和强调内容在相关性接近时优先保留;
  6. bm25_threshold过滤、按原文档顺序排序(保持阅读顺序而非分数序)、按文本去重,最后用基类clean_element输出清洗后的 HTML 块。

0.4.0 中对页面标题、meta 标签、描述的增强正体现在第 125-159 行的extract_page_query回退链上:即使用户不传查询,过滤器也能用页面自身的语义信号完成"自我相关性"判断。

选型建议(与发布说明及 README.md 的示例一致):

  • 无明确查询意图、只想拿到"干净正文"用于喂给 LLM →PruningContentFilter(更快、零依赖查询);
  • 有明确信息需求(如"这个产品支持哪些支付方式")→BM25ContentFilter(user_query=...)或进一步使用LLMContentFilter

五、User-Agent 生成器

0.4.0 新增的 User-Agent 生成器实现于 crawl4ai/user_agent_generator.py,提供三类生成器:

5.1 ValidUAGenerator:基于流行度统计的合法 UA

ValidUAGenerator(第 68-87 行)基于fake_useragent库生成真实出现过的 UA 字符串,generate方法支持约束参数:

from crawl4ai.user_agent_generator import ValidUAGenerator gen = ValidUAGenerator() # 默认:Chrome/Firefox/Edge + Windows/Mac OS X + 桌面端,随机取一个 ua = gen.generate() # 定制:只取 Firefox,最低版本 110 ua = gen.generate(browsers=["Firefox"], os=["Windows"], min_version=110.0)

参数还包括platforms(如["desktop"])与fallback(拉取数据失败时返回的兜底 UA,默认为一个 Linux Chrome 116 的 UA)。

5.2 OnlineUAGenerator:实时抓取最常见 UA

OnlineUAGenerator(第 89-139 行)在初始化时请求公开的用户代理统计站点,解析 JSON 得到带真实占比(pct)的 UA 列表,随后可按pct_threshold(占比阈值)、browsersosplatforms过滤并返回首条记录({'ua': ..., 'pct': ...})。适合需要"与真实流量分布一致"的场景。注意该生成器依赖外部网络可用。

5.3 UserAgentGenerator:组件化拼装与 Client Hints

UserAgentGenerator(第 143-414 行)把 UA 拆成可约束的组件:桌面/移动平台字符串(Windows 10 64/32 位、macOS、Linux、Android 品牌机型、iOS 等)、浏览器组合栈(1-3 段浏览器/渲染引擎标识)、以及 Chrome/Edge/Safari/Firefox 的版本列表。generate方法接受:

from crawl4ai.user_agent_generator import UserAgentGenerator gen = UserAgentGenerator() ua = gen.generate(device_type="desktop", os_type="windows", browser_type="chrome", num_browsers=3) print(ua) # Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 # (KHTML, like Gecko) Chrome/118.0.5993.117 ...

其中device_type"desktop"/"mobile")、os_type"windows""macos""linux""android""ios")、device_brand(如"iphone""pixel")、browser_type"chrome"/"edge"/"safari"/"firefox")、num_browsers(1-3,控制浏览器标识段数)。

generate_with_client_hints(第 344-348 行)会额外解析 UA 并生成与之匹配的Sec-CH-UA请求头值(如"Chromium";v="118", "Google Chrome";v="118", "Not_A Brand";v="8"),使 UA 与 Client Hints 保持一致,这对通过现代浏览指纹一致性检查尤为关键。

5.4 与 BrowserConfig 集成:每请求随机 UA

框架层在 crawl4ai/async_configs.py 中为BrowserConfig暴露了user_agent_modeuser_agent_generator_config两个参数(第 755-757 行的文档说明):user_agent_mode="random"时启用随机化,user_agent_generator_config用于透传给生成器的约束。默认行为即发布说明所述——"每次请求随机化 UA,增加多样性,同时允许用户定制"。实际调用链见 crawl4ai/async_crawler_strategy.py:

# 在每次运行中:若用户未显式传 user_agent, # 且 config.magic 或 user_agent_mode == "random" 时 user_agent = ValidUAGenerator().generate( **(config.user_agent_generator_config or {}) )

命令行侧同样支持该能力,crawl4ai/cli.py 的示例即:

crwl https://example.com -b "headless=true,viewport_width=1280,user_agent_mode=random"

六、多线程/并发环境下的锁机制

0.4.0 的另一项改进是"为并行处理环境增加更好的线程锁"。从源码结构看,这一能力体现在多个关键组件的锁设计上,例如 crawl4ai/browser_manager.py:

  • BrowserManager使用类级懒初始化锁_get_lock(第 596-605 行),并在锁上记录所属事件循环(_lock_loop),当检测到事件循环切换时重建锁,避免跨 loop 复用asyncio.Lock的经典陷阱;
  • 全局页面锁_get_global_lock(第 691-698 行)保护页面级共享资源;实例级_contexts_lock_page_lock_pending_cleanup_lock(第 736-756 行)分别保护上下文池、页面获取与清理流程;
  • LRU 上下文淘汰方法_evict_lru_context_locked(第 1435 行附近)明确标注"必须在持有_contexts_lock时调用",从源码结构看属于典型的锁内临界区约定。

此外 crawl4ai/async_database.py 中pool_lock/init_lock保护连接池获取与初始化,crawl4ai/async_webcrawler.py 第 157 行提供了thread_safe选项:self._lock = asyncio.Lock() if thread_safe else None,在共享爬虫实例时串行化arun调用。这些锁共同保证了多协程、多任务并行抓取时状态的一致性与稳定性。

七、实战示例:使用 PruningContentFilter 抽取干净正文

README.md 给出了 0.4.0 推广的两种过滤器用法,可直接运行(适用前提:已安装当前版本 Crawl4AI 并执行过crawl4ai-setup浏览器安装):

import asyncio from crawl4ai import AsyncWebCrawler, BrowserConfig, CrawlerRunConfig, CacheMode from crawl4ai.content_filter_strategy import PruningContentFilter, BM25ContentFilter from crawl4ai.markdown_generation_strategy import DefaultMarkdownGenerator async def main(): browser_config = BrowserConfig( headless=True, verbose=True, user_agent_mode="random", # 0.4.0 起:每请求随机 UA user_agent_generator_config={}, # 可传 browsers/os/min_version 等约束 ) run_config = CrawlerRunConfig( cache_mode=CacheMode.ENABLED, markdown_generator=DefaultMarkdownGenerator( content_filter=PruningContentFilter( threshold=0.48, threshold_type="fixed", min_word_threshold=0, ) ), # 换成查询驱动过滤: # markdown_generator=DefaultMarkdownGenerator( # content_filter=BM25ContentFilter( # user_query="WHEN_WE_FOCUS_BASED_ON_A_USER_QUERY", # bm25_threshold=1.0, # ) # ), ) async with AsyncWebCrawler(config=browser_config) as crawler: result = await crawler.arun( url="https://docs.micronaut.io/4.9.9/guide/", config=run_config, ) print(len(result.markdown.raw_markdown)) print(len(result.markdown.fit_markdown)) # 过滤后的"干净"长度 if __name__ == "__main__": asyncio.run(main())

CLI 同样内建了这两种过滤器:crawl4ai/cli.py 支持通过过滤配置文件或--output markdown-fit选择策略——type: bm25时构建BM25ContentFilter(可配querythreshold(默认 1.0)、use_stemming),type: pruning时构建PruningContentFilter(默认threshold=0.48),并在内部为markdown-fit输出默认采用 pruning 配置。

调参经验(源自单测中的阈值梯度验证):页面导航/广告噪声多时提高threshold(如 0.7 只保留最高价值块),正文稀疏或结构复杂时降低(如 0.3);短标签(按钮、时间戳)多时给min_word_threshold设 5~10 的地板值。

八、变更文件清单与实验性声明

按发布说明,0.4.0 的变更落点为:

  • crawl4ai/content_filter_strategy.py:加入基于评分的剪枝算法(PruningContentFilter);
  • README.md:补充PruningContentFilter用法(当前仓库对应 README-first.md 中的示例保留同一写法);
  • tests/async/test_content_filter_prune.py:覆盖多种剪枝场景、阈值梯度、畸形 HTML 与性能断言;
  • tests/async/test_content_filter_bm25.py:扩展 BM25 的边界用例(含畸形 HTML 输入)。

发布说明还保留了明确的边界提醒:PruningContentFilter当时处于实验性开发阶段。其默认阈值 0.48 与五维权重表都是启发式常量,面对非常规页面结构(如单列流式布局、大量嵌套span)时可能过度剪枝或保留噪声,建议按上文调参梯度在真实目标页面上验证后再固化配置。

九、小结

0.4.0 为 Crawl4AI 补齐了"无需查询意图的高质量正文抽取"(PruningContentFilter 的密度/链接/标签/语义四重评分)、"查询驱动的精准过滤"(BM25 + 页面元数据回退 + 标签权重)、"请求指纹多样化"(三种 UA 生成器 +user_agent_mode="random"+ Client Hints 一致性)与"并发稳定性"(浏览器管理器多级锁、thread_safe选项)四个能力维度。在当前 0.9.0 代码库中,这些类与参数均保持可用,本文给出的参数表、源码位置与测试路径可直接作为二次开发和调参的索引。

【免费下载链接】crawl4ai🚀🤖 Crawl4AI: Open-source LLM Friendly Web Crawler & Scraper. Don't be shy, join here: https://discord.gg/jP8KfhDhyN项目地址: https://gitcode.com/GitHub_Trending/craw/crawl4ai

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/7 7:24:57

Qt+QCustomPlot实时数据可视化动态曲线绘制与频谱分析工程详解

简介&#xff1a;这是一份基于Qt框架的动态曲线绘制完整示例工程&#xff0c;面向需要实现实时数据可视化的Qt开发者与学习者&#xff0c;演示如何借助QCustomPlot库在同一图表中绘制并动态更新多条曲线。压缩包体量轻巧&#xff0c;仅242KB&#xff0c;共9个文件&#xff0c;涵…

作者头像 李华
网站建设 2026/9/7 7:23:56

自动驾驶仿真测试场景设计:概念、方法与工程实践

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/7 7:22:25

猫抓资源嗅探扩展:在网页上找到视频源一键下载

猫抓资源嗅探扩展&#xff1a;在网页上找到视频源一键下载 【免费下载链接】cat-catch 猫抓 浏览器资源嗅探扩展 / cat-catch Browser Resource Sniffing Extension 项目地址: https://gitcode.com/GitHub_Trending/ca/cat-catch 你在浏览器里看一段教程视频&#xff0c…

作者头像 李华
网站建设 2026/9/7 7:22:04

高通9xxx平台modem功耗调试实战:从电流曲线到协议日志的定位方法

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/7 7:18:25

GaussDB开发入门:DataStudio下载、连接与使用全攻略

简介&#xff1a;华为高斯GAUSS数据库的Data Studio工具包现提供下载&#xff0c;面向数据库管理员、开发人员及大数据运维人群&#xff0c;适合需要建设数据仓库、处理大规模计算任务的场景。压缩包共521个文件&#xff0c;约148.3MB&#xff0c;内含jar、class、exe、dll等程…

作者头像 李华
网站建设 2026/9/7 7:17:36

3步搞定离线语音转文字:Buzz从安装到导出SRT的完整路径

3步搞定离线语音转文字&#xff1a;Buzz从安装到导出SRT的完整路径 【免费下载链接】buzz Buzz transcribes and translates audio offline on your personal computer. Powered by OpenAIs Whisper. 项目地址: https://gitcode.com/GitHub_Trending/buz/buzz 周五例会录…

作者头像 李华