
Python 用 BeautifulSoup 提取纯文本最稳
直接丢掉 HTML 标签、保留段落结构又不乱码,BeautifulSoup 是目前最靠谱的起点。别用正则硬扒,<p></p> 嵌套 <span></span> 再裹 <strong></strong> 时,正则会漏内容或炸开换行。
实操建议:
- 用
html.parser解析器,不用lxml(除非你明确装了且需要更快解析),避免因依赖缺失导致ImportError: No module named 'lxml' - 调
.get_text()时加参数:separator=' '防止相邻标签文字粘连,strip=True去首尾空格 - 如果原文有换行语义(比如
<br>或多个<p></p>),加preserve_whitespace=False(默认就是 False,但显式写出来防误读)
from bs4 import BeautifulSoup html = "<p>Hello<span>World</span></p><p>Next line</p><p><span>立即学习</span>“<a href="https://pan.quark.cn/s/cb6835dc7db1" style="text-decoration: underline !important; color: blue; font-weight: bolder;" rel="nofollow" target="_blank">前端免费学习笔记(深入)</a>”;</p>" soup = BeautifulSoup(html, "html.parser") txt = soup.get_text(separator=' ', strip=True) # → "Hello World Next line"
Node.js 用 cheerio 而不是 jsdom
cheerio 更轻、更快、API 类 jQuery,适合只做提取的场景;jsdom 模拟完整浏览器环境,启动慢、内存高,还容易因 document.write 或脚本执行报错中断。
常见错误现象:
- 用
jsdom读取含内联<script></script>的页面时,抛出ReferenceError: window is not defined -
cheerio.load(html).text()默认把所有标签内容挤成一行,没换行——得手动选元素再拼接
正确做法:
- 用
$('p').map((i, el) => $(el).text()).get().join('\n')保持段落分隔 - 遇到
或—等实体,加require('entities').decode处理,否则输出是原样字符串
命令行快速转换:lynx 比 w3m 更干净
Linux/macOS 下临时转一个文件,lynx -dump -nolist -stdin 输出最接近人工阅读效果:自动缩进列表、保留标题层级、过滤导航栏和广告区。而 w3m -dump 容易把链接 URL 和文字混在一起,比如 GitHub [1] 后面还跟一堆脚注。
使用场景:
- CI 脚本里批量处理静态 HTML 报告 → 加
-assume-charset=utf-8防乱码 - 输入含中文但终端 locale 是
C时,lynx会崩,先运行export LANG=zh_CN.UTF-8 - 不要用
html2text:它默认把所有链接转成行尾括号形式,干扰正文阅读
编码和换行符是隐形杀手
HTML 文件本身可能是 GBK、ISO-8859-1 或带 BOM 的 UTF-8,但多数工具默认按 UTF-8 读——结果中文全变 。更麻烦的是,Windows 的 \r\n 在某些解析器里会被当两个换行处理。
关键检查点:
- 用
file -i filename.html看真实编码,别信后缀或 meta 标签 - Python 里用
open(... , encoding='utf-8', errors='replace'),比盲目 decode 安全 - 输出 TXT 时统一用
\n(LF),别保留源文件的\r\n,否则 Git diff 或 grep 会误判
真正难的不是“怎么转”,而是转完后人眼扫一遍发现“这里少了个句号”“那个表格变成了一行乱码”——这时候得倒回去看原始 HTML 里是不是用了 display: none 的容器,或者文字藏在 data-* 属性里。这种细节,没有通用解法,只能结合具体 HTML 结构补规则。











