根本原因是elementtree默认编码与xml实际编码不匹配,需显式指定encoding参数:用open(filename, encoding="xxx")读取后传给et.parse(),或对bytes输入et.fromstring()时指定parser=et.xmlparser(encoding="xxx")。

为什么 xml.etree.ElementTree 读中文XML会乱码?
根本原因不是 ElementTree 本身不支持中文,而是它默认按系统编码(如 Windows 的 cp936)或 UTF-8 BOM 检测逻辑误判编码。当你用 ET.parse() 直接传入文件路径时,底层调用的是 open() 默认编码,而 Python 3.7+ 的 open() 在无显式 encoding 参数时不会自动识别 XML 声明中的 encoding="gbk" 或 encoding="utf-8"。
用 open() 显式指定 encoding 再传给 ET.parse()
这是最稳妥、兼容性最好的做法,绕过自动编码探测的不可靠性:
- 先用
open(filename, encoding="utf-8")或open(filename, encoding="gbk")读取为字符串,再用ET.fromstring() - 或者用
ET.parse()接收文件对象(而非路径),例如:with open("data.xml", encoding="gbk") as f: tree = ET.parse(f) - 如果 XML 文件开头有
<?xml version="1.0" encoding="gb2312"?>,但文件实际是 UTF-8 无 BOM,encoding必须以文件真实编码为准,XML 声明会被忽略
遇到 UnicodeDecodeError: 'utf-8' codec can't decode byte 怎么办?
说明你当前用的 encoding 和文件实际编码不匹配。不要盲目改代码,先确认文件真实编码:
- 用命令行工具查:Linux/macOS 运行
file -i data.xml;Windows 可用 VS Code 打开后看右下角编码标识(如 “UTF-8 with BOM”、“GBK”) - 常见组合:
gbk/gb2312/gb18030用于旧中文系统生成的 XML;utf-8-sig用于带 BOM 的 UTF-8 文件(Python 中utf-8-sig会自动剥离 BOM) - 避免用
errors="ignore"粗暴跳过错误——这会导致中文被替换成 ,后续提取文本时无法恢复
从网络或字符串加载时,ET.fromstring() 的编码陷阱
如果 XML 来自 requests.get().text 或拼接的字符串,注意:requests 默认按 HTTP header 的 charset 解码,但有时不准;手动构造字符串时若含中文,必须确保字符串本身是 Unicode(Python 3 下 str 就是 Unicode),但若你用 bytes 对象传入 fromstring(),就必须明确声明编码:
- 正确(str 输入):
ET.fromstring("<root><name>张三</name></root>") - 正确(bytes + encoding):
ET.fromstring(b"<?xml version='1.0' encoding='gbk'?><root><name>张三</name></root>", parser=ET.XMLParser(encoding="gbk")) - 错误:
ET.fromstring(b"<root><name>\xd5\xc5\xc8\xfd</name></root>")—— 没指定 parser 编码,会按 UTF-8 解 bytes,必然失败
真正容易被忽略的点:XML 声明里的 encoding 属性只对解析器读取原始字节流时起作用,一旦你用字符串(str)传给 fromstring(),这个声明就完全失效了——它已经不是字节,而是解码后的 Unicode。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











