---
title: "06-html_to_text"
created: 2026-04-02
tags:
- 项目
aliases:
- html_to_text
---
# html_to_text.py
### `html_to_text.py` — 底层 HTML 清洗
最底层工具,被多个上层模块调用:HTML 转纯文本,对 `
` 按行合并保留表格语义,清理 CSS/JS/隐藏元素/` ` 等噪音。
## 代码
```python
# -*-coding:utf-8-*-
# 功能:将HTML文本(含复杂表格)清洗转换为纯文本,去除标签、样式、脚本、注释等冗余内容
import re
from bs4 import BeautifulSoup, Comment
# 正则表达式:匹配需要在末尾添加换行符的HTML闭合标签,用于文本分段
brs_pattern = re.compile("||
|
|||||||||
|||||||||||||||")
class Html2txt():
"""HTML转纯文本工具类"""
def _html_text(self, _html):
"""
私有方法:提取HTML中的纯文本,并替换换行符为空格
:param _html: HTML字符串
:return: 处理后的纯文本
"""
# 解析HTML
soup = BeautifulSoup(_html, "lxml")
# 提取纯文本内容
_text = soup.get_text()
# 替换所有换行符为空格,去除首尾空白
return re.sub(r"(\r\n)|\n", " ", _text).strip()
def _table_text(self, table):
"""
私有方法:专门处理HTML表格,规整表格内容为纯文本(处理单元格、行列对齐)
:param table: BeautifulSoup的table节点对象
:return: 处理后的表格纯文本
"""
# 查找嵌套表格,有则直接提取文本返回
_tables = table.find_all("table")
if _tables:
return table.get_text()
# 获取所有行
trs = table.find_all("tr")
if trs:
for tr in trs:
# 获取当前行所有单元格
tds = tr.find_all("td")
new_tds = []
if tds:
for td in tds:
# 格式化单元格HTML,去除多余换行
_html = td.prettify()
_html = re.sub(r"(\r\n+)|\n+", "", _html)
# 匹配标签并添加换行,用于分段
brs = brs_pattern.findall(_html)
for br in set(brs):
_html = _html.replace(br, br + "\n")
# 按换行分割处理
_brs = re.split(r"\n+", _html)
# 修正末尾闭合标签位置
if _brs[-1] == "":
_brs.pop(-1)
_brs[-1] = _brs[-1] + ""
# 过滤空内容并去除空白
_brs = [_br.strip() for _br in _brs if _br and _br.strip()]
# 再次修正闭合标签
if _brs[-1] == "":
_brs.pop(-1)
_brs[-1] = _brs[-1] + ""
new_tds.append(_brs)
if new_tds:
# 计算单元格最大列数,用于对齐不规则表格
_len = [len(t) for t in new_tds]
_max = max(_len)
data = []
_ldiff = [_l for _l in _len if _max != _l]
if _ldiff:
# 补全短单元格,使行列对齐
re_tds = []
for t in new_tds:
diff_len = _max - len(t)
if diff_len:
for _ in range(0, diff_len):
t.append(" | ")
re_tds.append(t)
# 行列转置并拼接
for i in [list(t) for t in zip(*re_tds)]:
data.append("".join(i))
elif _max > 1:
try:
# 正常行列转置
for i in [list(t) for t in zip(*new_tds)]:
data.append("".join(i))
except:
print("****", re_tds)
else:
# 单行数据直接拼接
data = [" ".join([k[0].strip() for k in new_tds if k[0]])]
# 提取每个单元格纯文本
data = [self._html_text(d) for d in data]
# 用处理后的文本替换原表格行
_re_str = "\n".join(data)
tr.replace_with(_re_str)
# 返回最终表格文本
return table.get_text()
def clear_tables(self, s):
"""
递归清理HTML中的所有表格,替换为规整文本
:param s: HTML字符串
:return: 清理表格后的文本
"""
soup = BeautifulSoup(s, "lxml")
# 移除HTML注释内容
comments = soup.findAll(text=lambda text: isinstance(text, Comment))
[comment.extract() for comment in comments]
# 查找所有table标签
tables = soup.findAll("table")
_text = soup.get_text()
if tables:
for table in tables:
# 跳过嵌套表格
if table.findAll("table"):
continue
# 处理单个表格
_text = self._table_text(table)
if _text:
# 用纯文本替换原table标签
table.replace_with(_text)
# 递归处理剩余表格
_text = soup.get_text()
self.clear_tables(_text)
return _text
def clean_html(self, s):
"""
对外核心方法:完整清洗HTML,转换为规范纯文本
:param s: 原始HTML字符串
:return: 最终纯文本
"""
# 匹配")
# 还原HTML转义字符
s = re.sub("<", "<", s)
s = re.sub(">", ">", s)
s = re.sub("&", "&", s)
# 移除", "", s)
# 移除设置了隐藏样式(display:none)的HTML元素
s = re.sub("(?is)<[^<]*?display\s*\:\s*none[^>]*?>[^<]*?\w*?>", "", s)
# 移除下拉选择框