etree.fromstring 默认使用 etree.xmlparser,不带任何预设参数,遇 malformed xml 直接抛 xmlsyntaxerror,不自动处理 encoding 声明,也不忽略空白或注释。

etree.fromstring 默认用什么 parser?
默认用 etree.XMLParser,不是 etree.HTMLParser,也不带任何预设参数。这意味着:遇到 malformed XML(比如未闭合标签、非法字符、编码声明不一致)会直接抛 XMLSyntaxError;不自动处理 encoding 声明;不忽略空白或注释——除非你显式配置。
常见错误现象:UnicodeDecodeError: 'ascii' codec can't decode byte(源字符串是 bytes 但含非 ASCII)、XMLSyntaxError: Document is empty(空字符串或纯空白)、XMLSyntaxError: Invalid character in attribute value(如属性里有未转义的 &)。
实操建议:
- 如果输入是
bytes,确保它和 XML 声明中的 encoding 一致(例如<?xml version="1.0" encoding="utf-8"?>),否则 parser 可能按系统默认编码(如 cp1252)误读 - 若不确定输入是否规范,别直接
fromstring(data),先用etree.XMLParser(recover=True) - recover=True 不等于“容错 HTML 解析”,它只对 XML 语法错误做尽力恢复(比如补闭合标签),但不会把
<div> 当合法元素——那是 <code>HTMLParser的事recover=True 能解决哪些问题?又不能解决什么?
它让 parser 在遇到严重语法错误时不抛异常,而是尝试构建一个尽可能完整的树。典型适用场景:抓取网页返回的“类 XML”片段(实际是混杂 HTML 的 XML 片段)、日志中截断的 XML、遗留系统输出的格式松散数据。
立即学习“Python免费学习笔记(深入)”;
但要注意:
-
recover=True对编码错误无效——UnicodeDecodeError仍会抛出,必须提前 decode 或传入正确编码的bytes - 它不会修复命名空间声明缺失导致的
Prefix not found错误 - 如果 XML 中有
引用外部 DTD,且网络不可达或 DTD 格式非法,<code>recover=True也救不了——需加resolve_entities=False - 性能略降(parser 需多轮试探),生产环境高频解析时建议只在必要时开启
怎么安全地传入 encoding 参数?
etree.fromstring()本身没有encoding参数。真正控制编码的是 parser 实例——通过etree.XMLParser(encoding=...)构造,再传给fromstring(data, parser=...)。常见误区:
- 把 UTF-8 编码的
bytes误当str传入:Python 3 下fromstring(b"<root></root>", parser=p)是 OK 的,但fromstring("<root></root>", parser=p)中 parser 的encoding参数会被忽略(因为 str 已解码) - parser 的
encoding和 XML 声明冲突时,lxml 优先信声明(除非设resolve_entities=False且声明非法) - Windows 上读文件常默认用
open(..., encoding="gbk"),结果把 UTF-8 文件当 GBK 解码成乱码str,再喂给fromstring——这时 parser 的encoding完全不起作用
实操建议:统一用
bytes+ 显式XMLParser(encoding="utf-8"),避免隐式解码干扰。HTML 片段该不该用 fromstring + XMLParser?
不该。哪怕片段看着像 XML(比如
<p><b>text</b></p>),只要它来自 HTML 上下文(无根元素、含自闭合标签如<br>、有<script></script>内 CDATA),XMLParser就会失败或行为异常。正确做法:
- 用
etree.HTMLParser()替代XMLParser() - 对应调用
etree.fromstring(html_bytes, parser=etree.HTMLParser())或更稳妥的etree.parse(io.BytesIO(html_bytes), etree.HTMLParser()) -
HTMLParser默认recover=True,且自动处理编码、script/style 内容、布尔属性(<input checked>)等 - 注意:
HTMLParser返回的树可能和原始 HTML 结构不完全一致(比如自动补),提取时得适配
最易被忽略的一点:同一个 parser 实例不能复用于不同编码的输入——parser 的
encoding是构造时绑定的,换数据就得换 parser,否则可能静默错解。 -










