本地文件用elementtree.parse(),网络xml字符串用fromstring();命名空间需显式声明或用".//tag"模糊匹配;text为空时应strip()判断,含子标签用itertext()拼接。

ElementTree.parse() 和 ElementTree.fromstring() 用哪个?
看数据来源。本地文件用 parse(),HTTP 响应体(比如 response.text)必须用 fromstring() —— 否则会报 ParseError: not well-formed (invalid token),因为 parse() 只认文件路径或 file-like 对象,不接受字符串。
-
parse("data.xml"):直接读磁盘文件,返回ElementTree实例 -
fromstring(response.text):处理网络请求拿到的 XML 字符串,返回根Element - 如果用了
requests.get().content(bytes),要先 decode 成 str 再传给fromstring(),否则报TypeError: expected str, bytes or os.PathLike object
查不到节点?小心命名空间(namespace)
很多 XML(尤其是 RSS、SOAP、Atom)带命名空间,比如 <rss xmlns="http://purl.org/rss/1.0/"></rss>。这时候直接写 root.find("item") 一定返回 None,因为默认 namespace 是空字符串,而实际节点属于另一个 namespace。
- 先提取 namespace:用
root.tag.split("}", 1)[0][1:]或正则r'xmlns="(.*?)"'粗略抓(不严谨但够用) - 查节点时必须带前缀:
ns = {"rss": "http://purl.org/rss/1.0/"}; root.find("rss:item", ns) - 省略 namespace 的暴力法:
root.find(".//item")(支持 XPath,但性能略低,且可能匹配到嵌套深层的同名节点)
text 属性为空?可能是换行或空白字符
XML 中换行缩进会被解析成文本节点,导致 elem.text 是 "\n " 而非你想要的内容。这不是 bug,是标准行为。
- 别直接判断
if elem.text:,改用if elem.text and elem.text.strip(): - 想安全取值:写个辅助函数
safe_text(elem): return elem.text.strip() if elem is not None and elem.text else "" - 如果节点内容含子标签(如
<description>Hello <b>world</b></description>),text只覆盖第一个文本段,后续要用elem.itertext()拼接
用 findall() 还是 iter()?性能和语义差别明显
findall() 只查直接子节点,iter() 深度遍历整棵树 —— 容易误用,尤其在结构不确定时。
- 明确层级关系(如所有
item都在channel下):用root.find("channel").findall("item") - 不确定嵌套深度(如任意位置的
link):用list(root.iter("link")),但注意它比findall()慢 2–3 倍(小 XML 不明显,万级节点要留意) - 避免
root.findall(".//item"):虽然写法短,但底层也是递归扫描,和iter()性能接近,且可读性更差
None 或空字符串,先盯住这两点,比重写整个解析逻辑快得多。Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











