用 golang.org/x/net/html 逐节点遍历 dom 树提取 textnode,跳过 script/style 等无效标签;对文本压缩空白、按字符密度(utf8.runecountinstring)过滤低质段落;gbk 编码需用 charset.newreaderlabel 或 simplifiedchinese.gbk 解码;并发时用 bytes.join 和 unsafe.string 优化性能。

如何用 Go 提取 HTML 中的正文文本(非标签内容)
直接用 strings.TrimSpace 或正则粗暴删标签会丢内容、留空行、混入 JS/CSS。Go 标准库不带 HTML 解析器,必须用 golang.org/x/net/html 逐节点遍历,只保留 textNode 类型节点,并跳过 script、style、noscript 等无效容器。
关键点是:不能依赖 innerHTML 字符串替换,必须走 DOM 树遍历;否则像 <div>Hello<span>World</span>
</div> 这种嵌套结构会漏掉部分文本。
- 用
html.Parse解析响应 body,注意传入io.LimitReader防止超大响应 OOM - 递归遍历时,遇到
Data字段且父节点不是被屏蔽标签时才收集文本 - 对收集到的每段文本调用
strings.Join(strings.Fields(...), " ")压缩空白,避免换行符和多余空格
Go 中去除网页噪声的实用阈值策略
纯文本提取后仍有导航栏、页脚、广告等干扰块。Go 没有现成的 Readability.js 移植版,得自己模拟“块密度”逻辑:按换行切分段落,统计每段有效字符数 / 总长度,过滤掉低于阈值(如 0.3)或长度过短()的行。
这不是精确算法,而是经验性降噪——比如页脚常含大量符号和短词(“© 2024 | 联系我们”),字符密度低;而正文段落通常中文占比高、标点少、长度适中。
- 别用固定行数剔除(如删前3行/后2行),网站结构差异太大
- 对每段调用
utf8.RuneCountInString算真实字数,别用len()(返回字节数) - 可加白名单关键词增强判断,比如某段含 “摘要”、“关键词”、“参考文献”,大概率是正文,即使密度略低也保留
处理 GBK 编码网页时的解码陷阱
国内不少老站点用 GBK,http.Get 返回的 *http.Response.Body 是原始字节流,若直接用 html.Parse 会 panic 报错 invalid UTF-8。Go 的 net/html 只接受 UTF-8 输入,必须先解码。
在 Go 中使用 google/wire 实现编译时依赖注入——wire.NewSet、wire.Build、wire.Bind(接口→实现)、wire.Struct、wire.Value、wire.Interface
不能依赖 Content-Type header 的 charset 字段——它常为空或错误(比如声明 UTF-8 实际是 GBK)。稳妥做法是用 golang.org/x/net/html/charset 自动探测,或对常见中文站点硬编码 fallback。
- 用
charset.NewReaderLabel包装 Body,传给html.Parse - 若探测失败,fallback 到
simplifiedchinese.GBK.NewDecoder().Bytes(需引入golang.org/x/text/encoding/simplifiedchinese) - 解码后务必检查错误,
nil不代表成功——某些 GBK 乱码字节会被静默替换为 ,导致后续文本提取错位
并发爬取时文本去噪的内存与速度权衡
开 10 个 goroutine 同时解析 HTML,每个都做全文本提取+密度过滤,容易触发 GC 频繁或内存尖峰。尤其当页面含大量图片 URL、JS 注释、重复导航 HTML 片段时,中间字符串对象堆积快。
真正卡点不在正则或遍历慢,而在字符串拼接和切片重分配。Go 的 strings.Builder 能缓解,但更关键是控制输入规模。
- 在解析前用
bytes.Contains快速跳过明显无正文的响应(如含"404 Not Found"或"robots.txt"返回体) - 去噪阶段避免生成完整新字符串:用
[][]byte存每段原始字节,最后统一bytes.Join,减少 copy - 密度计算用
unsafe.String(Go 1.20+)绕过字符串构造开销,但仅限已确认合法 UTF-8 的片段
文本提取本身不复杂,难的是面对真实网页的脏数据容忍度——同一个算法,在知乎文章页可能效果很好,在政府旧站上却把标题全删了。多试几个样本,把阈值写成可配置变量,比追求“通用最优”更实际。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!










