应使用 lxml.html.fromstring() 替代 etree.fromstring(),因 html 解析器自动修复未闭合标签、补全结构并返回标准 element 对象,支持 xpath/cssselect;而 etree 严格遵循 xml 规范,遇 等自闭合标签直接报 xmlsyntaxerror。

lxml 默认拒绝解析未闭合标签,直接报 XMLSyntaxError;想让它“将错就错”继续解析,得换用 html 模块而非 etree,并明确告知它:这不是 XML,是 HTML。
为什么 etree.parse() 一遇到 <img alt="Python lxml解析不规范XML 如何处理未闭合的HTML/XML标签" > 就崩溃
etree.parse() 是为规范 XML 设计的,严格遵循 XML 规则:所有标签必须闭合、大小写敏感、必须有唯一根节点。像 <img src="a.jpg" alt="Python lxml解析不规范XML 如何处理未闭合的HTML/XML标签" > 或 <br> 这类 HTML 中合法但 XML 中非法的自闭合写法,在 etree 眼里就是语法错误。
常见错误现象:XMLSyntaxError: Opening and ending tag mismatch 或 NoneType is not callable(因解析失败返回 None 后调用方法)
- 使用场景:抓取网页源码、解析用户提交的富文本、处理老旧 CMS 导出内容
- 参数差异:
etree.parse()读文件,etree.fromstring()读字符串;但两者都走 XML 解析器,同样拒收不规范标签 - 性能影响:HTML 解析器比 XML 解析器稍慢,但对千行级文档基本无感;兼容性反而更好——它本就为容忍而生
改用 html.fromstring() 是最简解法
lxml.html 模块底层调用的是 libxml2 的 HTML 解析器,会自动修复缺失闭合、补全 、标准化属性大小写,结果仍是标准 Element 对象,后续用 .xpath() 或 .cssselect() 完全不受影响。
立即学习“Python免费学习笔记(深入)”;
- 实操建议:把所有
from lxml import etree替成from lxml import html,再把etree.fromstring(text)换成html.fromstring(text) - 注意:不要混用——
html.fromstring()返回的对象不能传给etree.tostring()直接用,但可传给html.tostring() - 如果原始内容是 XML 片段(比如只有
<div> <p>hello</p>),<code>html.fromstring()仍能处理;而etree.fromstring()会因缺少根节点报错from lxml import html doc = html.fromstring('<div>@@##@@<p>test<br></p>') print(doc.xpath('//img/@src')) # ['x'] —— 成功提取需要保留原始标签大小写或禁用自动修复?别用
htmlHTML 解析器默认会把
<img src="x" alt="Python lxml解析不规范XML 如何处理未闭合的HTML/XML标签" >转成小写<img src="x" alt="Python lxml解析不规范XML 如何处理未闭合的HTML/XML标签" >,也会补全缺失的和。如果你在做 HTML 格式校验、diff 对比,或必须保持原样输出,这种“好心”反而坏事。- 此时只能退回到
etree,但需预处理:用正则或html.parser先做最小修复(如把<img src="x" alt="Python lxml解析不规范XML 如何处理未闭合的HTML/XML标签" >替成<img alt="Python lxml解析不规范XML 如何处理未闭合的HTML/XML标签" >),再交给etree - 更稳妥的做法是用
etree.XMLParser(recover=True),但它只对部分错误有效(比如缺失结束标签),对孤立标签如<img alt="Python lxml解析不规范XML 如何处理未闭合的HTML/XML标签" >仍可能失败 - 兼容性提示:libxml2 的
recover=True在旧版本中行为不稳定,不同系统编译的 lxml 可能表现不一
真正麻烦的不是怎么修,而是你得先判断:这到底是 HTML 还是假扮成 XML 的 HTML?如果连文档声明都写着
,还硬用 <code>etree,那不是严谨,是给自己加戏。 - 此时只能退回到











