查看: 222|回复: 0

Python爬虫HTML预处理流水线:BOM编码清洗与注释标签移除

[复制链接]
发表于 2 小时前 | 显示全部楼层 |阅读模式
爬虫拿到 HTTP 返回的 HTML 源码后,不能直接进入解析阶段。原始页面可能带 UTF-8 BOM、空白、注释、转义字符和不规范标签,直接解析或提取文本容易出现乱码、匹配失败和 DOM 异常。HTML 预处理的目标不是压缩,而是在正式解析前修复脏数据、消除干扰项,为 XPath、CSS 选择器和文本提取提供干净输入。

预处理顺序与主要工作
一套标准流程的顺序很关键:二进制预处理 -> 编码识别与解码 -> 文本清洗 -> 标签规范化 -> 可选过滤。具体包括:剔除 UTF-8 BOM、截断超长响应、过滤无效二进制头部;把 bytes 转为字符串并解决乱码;移除注释、多余换行和空格;补全残缺标签、处理转义字符;按需移除 script/style/noscript 等无用标签,降低解析压力。重点提醒:应先做 bytes 处理,再解码,最后做文本清洗。不要先解码再处理 BOM,否则会引入 \ufeff 字符。

第一步:原始二进制处理,清除 UTF-8 BOM
Windows 服务器或记事本生成的网页,开头可能带 b'\xef\xbb\xbf'。它不属于 HTML 正文,会干扰魔数判断和前缀匹配,lstrip() 也无法自动移除。可以在解码前写一个函数:
  1. def strip_bom_and_prefix_whitespace(raw_bytes: bytes) -> bytes:
  2.     if raw_bytes.startswith(b'\xef\xbb\xbf'):
  3.         raw_bytes = raw_bytes[3:]
  4.     raw_bytes = raw_bytes.lstrip(b' \r\n\t')
  5.     return raw_bytes
复制代码
这一步适合放在 detect_file_type 之前执行,在解码前处理性能更高,也能规避解码异常。

第二步:编码识别,bytes 转文本
很多网页 Content-Type 里写的编码和页面 meta 声明不一致,直接用 resp.content.decode('utf-8') 大概率会乱码。可以使用 cchardet 或 chardet 自动探测编码:
  1. pip install cchardet
复制代码
  1. import cchardet
  2. def decode_html(raw_bytes: bytes) -> str:
  3.     detect_result = cchardet.detect(raw_bytes)
  4.     encoding = detect_result['encoding'] or 'utf-8'
  5.     try:
  6.         return raw_bytes.decode(encoding)
  7.     except Exception:
  8.         return raw_bytes.decode('utf-8', errors='replace')
复制代码
更稳妥的做法是优先从 response headers、html meta 标签中提取 charset,其优先级高于自动探测,准确率通常更高;自动探测作为兜底。

第三步:文本清洗,去除注释与多余空白
文本清洗要区分两种场景:一是保留页面结构,只删除注释、合并多余空白,适合解析;二是强压缩,删除标签间空白,适合存储和文本比对,不建议用于解析。不要用简单正则全局删除空白,因为 pre、textarea、script、style 内部的空白不能随意清除。例如:
  1. import re
  2. import htmlmin
  3. def clean_html_text(html: str, remove_comments=True) -> str:
  4.     if remove_comments:
  5.         html = re.sub(r'<!--[\s\S]*?-->', '', html)
  6.     html = htmlmin.minify(html, remove_comments=False, remove_all_empty_space=False)
  7.     return html
复制代码
如果只需要提取正文文本,不需要 JS 和 CSS,可以删除 script、style 标签,减少解析开销:
  1. from bs4 import BeautifulSoup
  2. def remove_useless_tags(html: str) -> str:
  3.     soup = BeautifulSoup(html, 'html.parser')
  4.     for tag in soup(['script', 'style', 'noscript']):
  5.         tag.decompose()
  6.     return str(soup)
复制代码
注意:移除 script/style 会改变页面 DOM 结构。如果业务需要执行 JS 或提取内嵌 CSS,不能使用这一步。

完整预处理流水线示例
把上述步骤组合到 requests 爬虫中,可以形成可复用的预处理函数。下面示例使用 requests、cchardet、htmlmin 和 BeautifulSoup,并需要导入 re:
  1. import re
  2. import requests
  3. import cchardet
  4. import htmlmin
  5. from bs4 import BeautifulSoup
  6. def preprocess_html(resp: requests.Response) -> str:
  7.     raw_bytes = resp.content
  8.     if raw_bytes.startswith(b'\xef\xbb\xbf'):
  9.         raw_bytes = raw_bytes[3:]
  10.     raw_bytes = raw_bytes.lstrip(b' \r\n\t')
  11.     detect_result = cchardet.detect(raw_bytes)
  12.     encoding = detect_result['encoding'] or 'utf-8'
  13.     try:
  14.         html_str = raw_bytes.decode(encoding)
  15.     except Exception:
  16.         html_str = raw_bytes.decode('utf-8', errors='replace')
  17.     html_str = re.sub(r'<!--[\s\S]*?-->', '', html_str)
  18.     soup = BeautifulSoup(html_str, 'html.parser')
  19.     for tag in soup(['script', 'style']):
  20.         tag.decompose()
  21.     html_str = str(soup)
  22.     html_str = htmlmin.minify(html_str, remove_comments=False, remove_all_empty_space=False)
  23.     return html_str
  24. if __name__ == '__main__':
  25.     r = requests.get('https://example.com')
  26.     clean_html = preprocess_html(r)
  27.     print(clean_html)
复制代码

常见踩坑点
BOM 处理时机:BOM 必须在 bytes 阶段处理,解码后会变成 \ufeff,容易干扰文本匹配。编码冲突:HTTP Header 的 charset、meta 标签 charset、页面实际编码三者可能不一致,自动探测只能兜底,优先解析 meta 标签。正则不能万能:不要手写正则删除标签,HTML 不是规则文本,正则容易破坏 DOM,标签删除交给 BeautifulSoup。预处理不等于压缩:做 XPath/CSS 选择器解析时不要使用强压缩模式,体积虽小但调试困难,且极少提升解析速度。转义字符:&lt;、&amp; 这类实体一般保留原样,只有提取纯文本展示时才调用 html.unescape()。异常页面:部分网页存在不闭合标签,BS4 会自动修复,这也是预处理的一部分。

不同业务场景的预处理策略
网页文件类型判断:只做二进制 BOM 清洗,不解码,直接用原始 bytes 做魔数判断。DOM 解析、字段提取:BOM 清洗 -> 解码 -> 删除注释 -> 移除 script/style -> 轻量空白规整。网页归档存储:在上述基础上开启 htmlmin 强压缩,减小存储体积。网页正文相似度比对:全部预处理完成后,再提取纯文本,消除换行空格带来的干扰。

小结
HTML 预处理不是简单删空格,而是一套分层清洗流水线:二进制预处理优先,然后处理编码,再做 DOM 清洗。根据业务选择清洗力度,类型检测尽量不解码;DOM 解析用 BS4 安全移除无用标签;归档场景再开启压缩。在爬虫项目中,把 BOM 清洗、编码探测、注释清理、无用标签移除封装成独立函数,可以减少后续解析环节的诡异 bug。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

指导单位

江苏省公安厅

江苏省通信管理局

浙江省台州刑侦支队

DEFCON GROUP 86025

Hacking Group 021A

旗下站点

态势感知中心

应急响应中心

红盟安全

联系我们

官方QQ群:112851260

官方邮箱:security#ihonker.org(#改成@)

官方核心成员

关注微信公众号

Archiver|手机版|小黑屋| ( 沪ICP备2021026908号 )

GMT+8, 2026-9-18 13:33 , Processed in 0.020265 second(s), 18 queries , Gzip On, Redis On.

Powered by ihonker.com

Copyright © 2015-现在.

  • 返回顶部