a
This commit is contained in:
@@ -555,3 +555,68 @@ crawl 流程:
|
||||
1. `wechat_crawl.py` 是独立路由 `/api/wechat-crawl/`,有自己的 preview/save 两阶段流程,是「微信专用采集器」而非「散落的站点特判逻辑」,不存在重复规则问题
|
||||
2. 微信的提取逻辑会以 `WechatExtractor` 策略类形式注册到 `crawl_strategies.py`,供通用入口(`universal_fetch` / `crawl_article`)遇到微信 URL 时兜底复用——这是**新增复用**,不改动 wechat_crawl.py 本体
|
||||
3. 若未来想让 wechat_crawl.py 内部也复用策略类,属于可选优化(消除与 crawl.py 微信段的重复),不在本次重构范围
|
||||
|
||||
---
|
||||
|
||||
## 九、正文噪音过滤(Pruning 思路,已落地)
|
||||
|
||||
### 9.1 背景与动机
|
||||
|
||||
HTML → Markdown 转换面对的是整页 DOM,导航栏、侧栏、评论区、相关推荐、
|
||||
广告等噪音容器会一并进入正文 Markdown,污染文章内容(CSDN 实测整页文本
|
||||
7505 字符,正文仅 2714 字符,噪音占 64%)。
|
||||
|
||||
参考 crawl4ai 的 PruningContentFilter(`/home/ubuntu/forgithub/crawl4ai`
|
||||
`/crawl4ai/content_filter_strategy.py`)实现本地化方案。
|
||||
|
||||
### 9.2 评分模型
|
||||
|
||||
对 DOM 递归评分,低于阈值删除:
|
||||
|
||||
```
|
||||
score = 0.4*text_density + 0.2*link_density + 0.2*tag_weight
|
||||
+ 0.1*class_id_weight + 0.1*text_length
|
||||
```
|
||||
|
||||
- `text_density` = 节点文本 / 节点 HTML 长度,越纯文本越高
|
||||
- `link_density` = 1 - 链接文本占比,链接越少越像正文
|
||||
- `tag_weight`:p/article/section/main=1.0~1.5,div/li/td=0.5
|
||||
- `text_length` = min(log(文本长度+1), 5.0),长度项封顶
|
||||
|
||||
### 9.3 相对 crawl4ai 原版的两处修正
|
||||
|
||||
1. **长度项封顶 5.0**:原版 `log(text_len+1)` 无上限,超大噪音容器
|
||||
(如 3600+ 字符的相关推荐列表)得分 0.90 远超阈值 0.48 而残留;
|
||||
封顶后大容器不再因体量大而误判为正文。
|
||||
2. **负面类名硬删**:原版对命中负面模式(recommend/comment/sidebar/ads…)
|
||||
的类名仅 -0.5 小惩罚;本实现直接删除整个子树,因为类名/ID 命中
|
||||
负面模式的容器几乎必然是噪音。
|
||||
|
||||
### 9.4 安全兜底(质量门控)
|
||||
|
||||
剪枝后若正文文本 < 300 字符,或 < 原文本的 20%,判定为疑似误删,
|
||||
回退返回原 HTML。对已定位正文容器的局部 HTML(如 CSDN `#content_views`)
|
||||
调用时无副作用,正文容器内节点评分普遍高于阈值。
|
||||
|
||||
### 9.5 接入点(crawl.py + universal_crawl.py)
|
||||
|
||||
新增 `backend/routers/content_prune.py`,`prune_html_noise()` 在**两个
|
||||
HTML → Markdown 转换函数的统一入口**调用(`fix_encoding` 之后):
|
||||
|
||||
- `crawl.py::html_to_markdown()` —— 覆盖 `/api/crawl/` 旧轨
|
||||
- `crawl.py::convert_spa_html_to_markdown()` —— 覆盖 Playwright SPA 轨
|
||||
|
||||
`universal_crawl.py` 的 `_legacy_extract()` 调用上述两个函数(站点特判
|
||||
分支传已提取的正文容器,SPA/通用分支传整页),**自动获得剪枝,无需
|
||||
重复调用**(避免双重剪枝开销),仅在调用处加注释说明。
|
||||
|
||||
策略轨(`run_extractor → extractor.to_markdown`)同样经由 `crawl.py`
|
||||
转换函数获得剪枝。
|
||||
|
||||
### 9.6 验证结果
|
||||
|
||||
- 真实 CSDN 文章页:7505 → 2817 字符(-62%),`#content_views` 正文
|
||||
保留率 99.8%,博主/评论/点赞/分享/扫码等噪音关键词全部删除
|
||||
- 构造页面:导航/相关推荐/侧栏/评论区全部删除,正文与 `<pre><code>` 保留
|
||||
- 质量门控:剪后 2817 > 300 且 38% > 20%,正常通过
|
||||
- `test_crawl_strategies.py` + `test_crawl.py` 回归:6 passed,无回归
|
||||
|
||||
Reference in New Issue
Block a user