lxml库没有strip_tags函数,应使用etree.tostring(doc, method='text', encoding=None)提取纯文本,或用xpath('.//text()')获取文本节点列表后清洗。

lxml strip_tags 不存在,别白搜了
lxml 库压根没有 strip_tags 这个函数——这是很多人卡住的第一步。它常见于 Django 或 BeautifulSoup 的语境里,但在 lxml 中,你得用别的组合方式实现“去标签、留文本”。直接 import 或调用会报 AttributeError: module 'lxml.etree' has no attribute 'strip_tags'。
用 etree.tostring + method='text' 是最稳的替代方案
真正能干净提取纯文本(不含标签、保留换行和空格逻辑)的是 etree.tostring() 配合 method='text' 参数。它不是简单删标签,而是按 DOM 文本节点遍历拼接,对嵌套、注释、CDATA 都有合理处理。
- 必须传
encoding=None,否则返回 bytes,还得 decode,容易漏 - 结果里会有换行符和多余空白,因为 XML 原文里的文本节点就是这么存的
- 如果原文有实体(如
),method='text'不解码,得额外用html.unescape() - 不支持 XPath 过滤,想只取某部分文本得先用
xpath()定位元素,再对每个结果调用
from lxml import etree
doc = etree.fromstring('<div>Hello<b>World</b>!</div>')
text = etree.tostring(doc, method='text', encoding=None)
# → 'HelloWorld!'用 xpath('.//text()') 灵活但容易掉坑
这个方法能拿到所有文本节点,适合需要控制合并逻辑或跳过某些区域的场景,但默认行为很“诚实”:注释、处理指令、空白节点全出来,一不留神就多出空字符串或乱码。
- 结果是字符串列表,不是单个字符串,得自己
''.join()或过滤 -
//text()会抓到元素间的空白(比如换行缩进),常需filter(None, ...)或strip()清洗 - 如果 XML 里有 CDATA 块,它的内容会被当作文本节点原样返回;但注释节点不会被
//text()匹配到 - 性能略低于
method='text',尤其文档大时,因为要构造完整节点列表
texts = doc.xpath('.//text()')
clean_text = ''.join(t.strip() for t in texts if t.strip())
# 注意:这里 strip() 会吃掉所有前后空格,包括段落间有意义的缩进别用 re.sub(r'<.*?>', '', ...) 处理 XML
正则删标签在 XML 场景下属于高危操作:嵌套标签、属性含 >、CDATA、注释、自闭合标签都会让正则崩。哪怕看起来“这次能跑”,下次换个输入就出错,而且错误难以定位。
立即学习“Python免费学习笔记(深入)”;
- 例如
<img src="a>b" />会让re.sub(r'<.*?>', '')删掉从<img到后面第一个>的全部,破坏后续结构 - XML 声明(
<?xml ...?>)、DOCTYPE、命名空间声明全会被误伤 - 没有解析上下文,无法区分标签和普通文本里的尖括号(比如代码示例中出现的
<div>)
真要快速原型且确定输入绝对简单,可以临时用,但上线前必须换成 etree 方案。
真正麻烦的不是选哪个方法,而是得时刻记住:lxml 的文本提取永远依赖解析后的树结构,没 parse 就谈不上 clean。很多问题其实出在 etree.fromstring() 失败后还硬往下走,结果 doc 是 None,后面全报错。










