用 BeautifulSoup 提取纯文本最稳,但需用 get_text(separator=' ', strip=True) 或 separator='\n' 配合正则清洗空行;lxml 更快但需手动处理空白;JS 渲染页用 Playwright 等元素就位;中文乱码须强制指定 encoding 或用 content+from_encoding。

用 BeautifulSoup 提取纯文本最稳,但得先处理换行和空白
直接调用 get_text() 会把 HTML 中的换行、缩进、空格全堆成一团,段落粘连、标题和正文分不开是常见现象。实际用时必须加清洗步骤。
- 用
get_text(separator=' ', strip=True)替代默认调用,避免空格爆炸 - 若需保留段落结构,改用
get_text(separator='\n', strip=True),再对结果做re.sub(r'\n\s*\n', '\n\n', text)去掉多余空行 -
strip=True很关键——否则每个标签前后空格都会残留,尤其<div><p>内容</p></div>容易多出四五个空格
lxml 的 text_content() 比 BeautifulSoup 快,但不自动合并空白
如果你处理的是 GB 级 HTML 文件或高频批量任务,lxml 是更优选择,但它的 text_content() 返回原始拼接文本,不处理任何空白逻辑。
- 必须手动后处理:用
' '.join(text.split())压缩所有空白为单空格(适合摘要类场景) - 若要保留换行语义,得遍历节点,对
tail和text分别提取并插入换行符,比如<p>第一段</p><p>第二段</p>需靠p.tail判断是否换行 - 注意:
lxml默认不加载 DTD,遇到带实体引用的 HTML(如)可能报错,得加parser=etree.HTMLParser(recover=True)
遇到 JavaScript 渲染页面,requests + BeautifulSoup 直接失效
静态抓取拿不到 document.write 或 Vue/React 渲染后的内容,这不是解析器问题,是时机问题。
将调研报告、方案对比、数据分析、需求梳理、会议纪要、设计说明、代码评审、学习笔记等任务产物输出为可在浏览器直接打开的单文件 HTML,替代 Markdown 作为最终交付物。Markdown 在信息密度、视觉清晰度和可分享性上已跟不上 AI 产物的丰富度,HTML 能同时承载排版、表格、SVG 等。
- 优先查网站是否有 API 接口(Chrome DevTools → Network → XHR/Fetch),绕过渲染直接拿 JSON
- 非得跑浏览器,用
Playwright比Selenium启动快、内存低,且支持无头模式下直接page.inner_text('body') - 切忌在 Playwright 里等固定秒数(如
time.sleep(2)),改用page.wait_for_selector('main', state='visible')等真实元素就位
中文乱码、编码识别失败时,别依赖 requests.get().text
requests 自动猜编码经常翻车,特别是 GBK 编码的国内老站,.text 一读就是乱码,后续解析全崩。
立即学习“前端免费学习笔记(深入)”;
- 强制指定编码:
resp = requests.get(url); resp.encoding = 'gbk'; soup = BeautifulSoup(resp.text, 'html.parser') - 更稳妥的做法是用
resp.content(原始字节)传给解析器:BeautifulSoup(resp.content, 'html.parser', from_encoding='gbk') - 如果连 meta charset 都没写,用
chardet.detect(resp.content)['encoding']探测,但别无脑信——它对短文本准确率很低,建议结合文件头或网站地域经验判断


















