夜雪一千头像
关注

Python 如何对 HTML 进行预处理

前言

爬虫开发中,拿到 HTTP 返回的 HTML 原始源码并不是终点。原始页面经常夹杂 BOM 标记、多余空白、无效注释、转义字符、不规范标签,直接拿去解析、提取文本、做相似度对比或者文件类型判断,很容易踩各种隐形大坑。

HTML 预处理,本质是在正式解析之前,对原始网页做清洗、规整。它不等同于 HTML 压缩,压缩更多是为减小体积;预处理目标更宽泛:修复脏数据、消除干扰项,为后续 XPath / CSS选择器 / 文本提取提供干净可靠的输入。

本文结合爬虫实战,梳理一套完整的 HTML 预处理流水线,覆盖从原始 bytes 到干净文本的全流程。

HTML预处理一般要做哪些工作

一套标准预处理流程顺序(非常关键,顺序不能乱):

  1. 二进制预处理:剔除 UTF-8 BOM、截断超长响应、过滤无效二进制头部
  2. 编码自动识别 & 解码:把 bytes 转为字符串,解决网页乱码
  3. 清洗干扰内容:移除注释、多余换行/空格,按需压缩空白
  4. 标签规范化:补全残缺标签、处理转义字符
  5. 可选过滤:移除无用标签(script/style/noscript),减少解析压力

重点提醒:操作顺序建议:bytes处理 → 解码 → 文本清洗。不要先解码再处理BOM,会引入不必要的\ufeff字符。

第一步:原始二进制处理,清除UTF-8 BOM

网页由Windows服务器或记事本生成时,很容易在最前面带上b'\xef\xbb\xbf'
它不属于HTML正文,但是会干扰魔数判断、前缀匹配,lstrip()无法自动移除。

def strip_bom_and_prefix_whitespace(raw_bytes: bytes) -> bytes:
    # 移除UTF-8 BOM
    if raw_bytes.startswith(b"\xef\xbb\xbf"):
        raw_bytes = raw_bytes[3:]
    # 剔除文档开头空白(空格、换行、tab、回车)
    raw_bytes = raw_bytes.lstrip(b" \r\n\t")
    return raw_bytes

这一步对应我们之前写的detect_file_type函数,在解码之前执行,性能更高,规避解码异常

第二步:编码识别,bytes转文本

很多网页Content-Type里写的编码和页面meta声明不一致,直接用resp.content.decode("utf-8")大概率乱码。
推荐使用cchardet/chardet自动探测编码。

pip install cchardet
import cchardet

def decode_html(raw_bytes: bytes) -> str:
    detect_result = cchardet.detect(raw_bytes)
    encoding = detect_result["encoding"] or "utf-8"
    try:
        return raw_bytes.decode(encoding)
    except Exception:
        # 探测编码失败时兜底
        return raw_bytes.decode("utf-8", errors="replace")

小技巧:可以优先从response headers、html meta标签提取charset,优先级高于自动探测,准确率更高。

第三步:文本清洗,去除注释与多余空白

这里要区分两种场景:

  1. 保留页面结构,只删除注释、合并多余空白(推荐,用于解析)
  2. 强压缩,删除标签间空白(适合存储、文本比对,不建议用于解析)

❌ 禁止简单正则全局删除空白,<pre> <textarea> <script> <style>内部的空白不能随意清除。

import re
import htmlmin

def clean_html_text(html: str, remove_comments=True) -> str:
    if remove_comments:
        # 删除html注释,注意:不会处理script内部注释
        html = re.sub(r"<!--[\s\S]*?-->", "", html)
    # 轻量清洗,保留pre/script/style内部格式
    html = htmlmin.minify(html, remove_comments=False, remove_all_empty_space=False)
    return html

按需移除无用标签(爬虫常用)

如果我们只需要提取正文文本,不需要JS、CSS,可以直接删除script、style标签,减少解析开销:

from bs4 import BeautifulSoup

def remove_useless_tags(html: str) -> str:
    soup = BeautifulSoup(html, "html.parser")
    for tag in soup(["script", "style", "noscript"]):
        tag.decompose()
    return str(soup)

注意:移除script/style会改变页面DOM结构,如果你的业务需要执行JS、提取内嵌CSS,不能使用这一步。

完整预处理流水线示例(爬虫实战)

组合上面所有步骤,搭配requests,形成可直接复用的预处理函数:

import requests
import cchardet
import htmlmin
from bs4 import BeautifulSoup

def preprocess_html(resp: requests.Response) -> str:
    # 1. 获取原始二进制,清理BOM和前置空白
    raw_bytes = resp.content
    if raw_bytes.startswith(b"\xef\xbb\xbf"):
        raw_bytes = raw_bytes[3:]
    raw_bytes = raw_bytes.lstrip(b" \r\n\t")

    # 2. 编码探测并解码
    detect_result = cchardet.detect(raw_bytes)
    encoding = detect_result["encoding"] or "utf-8"
    try:
        html_str = raw_bytes.decode(encoding)
    except Exception:
        html_str = raw_bytes.decode("utf-8", errors="replace")

    # 3. 删除注释
    html_str = re.sub(r"<!--[\s\S]*?-->", "", html_str)

    # 4. 移除script/style标签(按需开启)
    soup = BeautifulSoup(html_str, "html.parser")
    for tag in soup(["script", "style"]):
        tag.decompose()
    html_str = str(soup)

    # 5. 轻量清洗多余空白
    html_str = htmlmin.minify(html_str, remove_comments=False, remove_all_empty_space=False)
    return html_str

if __name__ == "__main__":
    r = requests.get("[https://example.com](https://example.com)")
    clean_html = preprocess_html(r)
    print(clean_html)

常见踩坑点

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

不同业务场景预处理策略

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

小结

HTML预处理不是简单的“删空格”,而是一套分层清洗流水线:二进制预处理优先,然后处理编码,再做DOM清洗
根据业务选择清洗力度:类型检测尽量不解码;DOM解析用BS4安全移除无用标签;归档场景再开启压缩。

在爬虫项目中,把BOM清洗、编码探测、注释清理、无用标签移除封装成独立预处理函数,可以极大减少后续解析环节的各种诡异bug。

转载自 CSDN-专业IT技术社区

原文链接:https://blog.csdn.net/2201_75821470/article/details/165749416

文章来源转载

评论

赞0

评论列表

微信小程序
QQ小程序

关于作者

点赞数:0
关注数:0
粉丝:0
文章:0
关注标签:0
加入于:--