真正稳定的做法是先解码HTML实体,再交由BeautifulSoup解析,最后用get_text()提取;顺序错误会导致清洗不可靠。

别用正则硬删 <.></.>,90% 的翻车都从这开始。真正稳定的做法是:先解码 HTML 实体,再交由 BeautifulSoup 解析,最后用 get_text() 提取——顺序错了,清洗就不可靠。
为什么不能直接用 re.sub(r"<.>", "", text)</.>
这个正则看着简单,但遇到这些情况立刻失效:
-
<script>alert("hello > world")</script>:引号里的>会被误判为标签闭合 -
<img src="a.jpg" alt="photo>1">:属性值含>,正则提前截断 -
<br>、<hr>这类自闭合标签,或缺失闭合的<p>文本</p>,正则根本无法匹配完整结构 -
、—这类实体不会被还原,清洗后还留着&符号
BeautifulSoup.get_text() 的三个关键参数陷阱
get_text() 不是“开箱即用”,默认行为会悄悄吃掉你关心的信息:
- 不传
strip=True:首尾空格、换行全保留,后续==比对失败率飙升 - 不处理换行逻辑:默认把
\n、\t全压成空格,新闻段落、表格行间结构彻底丢失 - 没调
html.unescape():原始 HTML 里的你好会原样输出成乱码字符
正确写法示例:
使用 PptxGenJS 和 Python 解析,将结构化的 HTML/CSS 幻灯片内容转换为原生、可编辑的 PowerPoint(.pptx)演示文稿。
from bs4 import BeautifulSoup import html <p>def clean_html_text(html_str): if not isinstance(html_str, str): return ""</p><h1>先解码实体,再解析</h1><pre class="brush:php;toolbar:false;">decoded = html.unescape(html_str) soup = BeautifulSoup(decoded, "lxml") # 优先用 lxml,容错更强 # 显式控制空白:保留换行分隔,但压缩内部多余空格 text = soup.get_text(separator="\n", strip=True) # 再把连续空格/制表符替换成单空格,但不动 \n import re text = re.sub(r"[ \t\u3000]+", " ", text) return text
去重前必须做标准化,否则等于没洗
爬下来的数据里,“北京”、“ 北京 ”、“北京 ”、“北京”(全角空格)、“BEIJING”可能全指向同一项。直接 set(raw_list) 没意义:
- 大小写不统一 → 统一转
.lower() - 全角/半角空格、不间断空格(
\xa0)、零宽空格(\u200b)混用 → 用re.sub(r'[\s\u3000\xa0\u200b]+', ' ', s)归一 - 中文标点和英文标点混用(如“。” vs “.”)→ 若业务允许,可统一替换或剔除
- URL 中
http://和https://视为等价 → 标准化时统一转https://或去掉协议头再比对
标准化函数建议这样写(保留原始值用于溯源):
def normalize(s):
if not isinstance(s, str):
return s
s = html.unescape(s).strip()
s = re.sub(r'[\s\u3000\xa0\u200b]+', ' ', s)
s = re.sub(r'[^\w\s\u4e00-\u9fff.-]', '', s) # 保留中英文、数字、常见符号
return s.lower()
<h1>去重时用:</h1><p>unique_pairs = list(dict.fromkeys((normalize(x), x) for x in raw_list))
cleaned = [orig for norm, orig in unique_pairs]
</p>
最常被忽略的一点:清洗链顺序不能乱——必须是 html.unescape() → BeautifulSoup 解析 → get_text() → 空白标准化 → 实体/符号二次清理。中间跳一步,后面所有去重、NLP、入库都可能埋雷。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!










