查看: 144|回复: 3

Python读取XML文件:5种方法代码对比与选择指南

[复制链接]
发表于 1 小时前 | 显示全部楼层 |阅读模式
Python 提供了多种读取 XML 文件的库,从标准库中的 xml.etree.ElementTree 到第三方的高性能 lxml,各有适用场景。本文以一份包含国家信息的 test.xml 为例,演示五种主流方法的核心用法,并给出选型建议。

示例 XML 文件(test.xml)内容如下:
  1. <?xml version="1.0"?>
  2. <data>
  3.   <country name="Liechtenstein">
  4.     <rank>1</rank>
  5.     <year>2008</year>
  6.     <gdppc>141100</gdppc>
  7.     <neighbor name="Austria" direction="E"/>
  8.     <neighbor name="Switzerland" direction="W"/>
  9.   </country>
  10.   <country name="Singapore">
  11.     <rank>4</rank>
  12.     <year>2011</year>
  13.     <gdppc>59900</gdppc>
  14.     <neighbor name="Malaysia" direction="N"/>
  15.   </country>
  16. </data>
复制代码

方法一:xml.etree.ElementTree(标准库,轻量级)
ElementTree 是 Python 官方推荐的标准库模块,API 简洁,无需安装第三方包。它支持从文件路径或字符串解析,并提供 find/findall/iter 等便捷方法。
  1. import xml.etree.ElementTree as ET
  2. # 解析文件
  3. tree = ET.parse('test.xml')
  4. root = tree.getroot()
  5. # 解析字符串:ET.fromstring(xml_string)
  6. print(f"根节点标签: {root.tag}")
  7. for child in root:
  8.     print(f"子节点: {child.tag}, 属性: {child.attrib}")
  9.     for subchild in child:
  10.         print(f"  孙节点: {subchild.tag}, 文本: {subchild.text}")
  11. # findall 与 get 用法
  12. for country in root.findall('country'):
  13.     name = country.get('name')
  14.     rank = country.find('rank').text
  15.     print(f"国家: {name}, 排名: {rank}")
  16. # iter 迭代查找特定标签
  17. for neighbor in root.iter('neighbor'):
  18.     print(f"邻居: {neighbor.get('name')}, 方向: {neighbor.get('direction')}")
复制代码

方法二:xml.dom.minidom(标准库,完整 DOM)
minidom 实现了 W3C DOM 接口,将整个文档加载为内存树,适合需要随机访问或修改节点的场景。但内存占用较高,速度较慢。
  1. from xml.dom import minidom
  2. dom = minidom.parse('test.xml')
  3. root = dom.documentElement
  4. countries = root.getElementsByTagName('country')
  5. print(f"找到 {len(countries)} 个国家")
  6. for country in countries:
  7.     name = country.getAttribute('name')
  8.     print(f"国家: {name}")
  9.     rank = country.getElementsByTagName('rank')[0].firstChild.data
  10.     year = country.getElementsByTagName('year')[0].firstChild.data
  11.     print(f"  排名: {rank}, 年份: {year}")
  12.     for neighbor in country.getElementsByTagName('neighbor'):
  13.         print(f"  邻居: {neighbor.getAttribute('name')}, 方向: {neighbor.getAttribute('direction')}")
复制代码

方法三:BeautifulSoup(第三方库,灵活强大)
BeautifulSoup 原本用于 HTML 解析,但指定 XML 解析器后可完美处理 XML。安装命令:pip install beautifulsoup4,并需额外安装解析器(如 lxml-xml)。它支持 find_all、CSS 选择器,对格式不规范的文档容错性高。
  1. from bs4 import BeautifulSoup
  2. with open('test.xml', 'r', encoding='utf-8') as f:
  3.     soup = BeautifulSoup(f, 'xml')  # 或 'lxml-xml'
  4. print(f"根节点: {soup.data.name}")
  5. countries = soup.find_all('country')
  6. for country in countries:
  7.     print(f"国家: {country['name']}")
  8.     print(f"  排名: {country.rank.text}, 年份: {country.year.text}")
  9.     for neighbor in country.find_all('neighbor'):
  10.         print(f"  邻居: {neighbor['name']}, 方向: {neighbor['direction']}")
  11. # CSS 选择器
  12. for gdppc in soup.select('gdppc'):
  13.     print(f"人均GDP: {gdppc.text}")
复制代码

方法四:lxml.etree(第三方库,高性能)
lxml 在底层使用 C 扩展,速度极快,且完全兼容 ElementTree 的 API,同时支持 XPath 等高级查询。安装:pip install lxml。
  1. from lxml import etree
  2. tree = etree.parse('test.xml')
  3. root = tree.getroot()
  4. print(f"根节点: {root.tag}")
  5. for country in root:
  6.     print(f"国家属性: {country.attrib}")
  7. # XPath 查找所有 rank
  8. ranks = root.xpath('//rank')
  9. print("所有排名:")
  10. for rank in ranks:
  11.     print(f"  {rank.text}")
  12. # XPath 查找指定国家年份
  13. singapore_year = root.xpath('//country[@name="Singapore"]/year/text()')
  14. print(f"Singapore 年份: {singapore_year[0]}")
  15. # XPath 获取所有 neighbor 的 direction 属性
  16. directions = root.xpath('//neighbor/@direction')
  17. print(f"所有方向: {directions}")
复制代码

方法五:xml.sax(标准库,流式解析)
SAX(Simple API for XML)基于事件驱动,边读边解析,内存占用极低,适合处理超大型 XML 文件。但其代码编写相对繁琐,需要自定义 ContentHandler。
  1. import xml.sax
  2. class CountryHandler(xml.sax.ContentHandler):
  3.     def __init__(self):
  4.         self.current_data = ""
  5.         self.name = ""
  6.         self.rank = ""
  7.     def startElement(self, tag, attributes):
  8.         self.current_data = tag
  9.         if tag == "country":
  10.             self.name = attributes["name"]
  11.             print(f"\n国家: {self.name}")
  12.         elif tag == "neighbor":
  13.             print(f"  邻居: {attributes['name']}, 方向: {attributes['direction']}")
  14.     def characters(self, content):
  15.         if self.current_data == "rank":
  16.             self.rank = content
  17.         elif self.current_data == "year":
  18.             self.year = content
  19.     def endElement(self, tag):
  20.         if self.current_data == "rank":
  21.             print(f"  排名: {self.rank}")
  22.         elif self.current_data == "year":
  23.             print(f"  年份: {self.year}")
  24.         self.current_data = ""
  25. parser = xml.sax.make_parser()
  26. parser.setFeature(xml.sax.handler.feature_namespaces, 0)
  27. handler = CountryHandler()
  28. parser.setContentHandler(handler)
  29. parser.parse("test.xml")
复制代码

方法对比一览
- xml.etree.ElementTree:标准库,内存中等,速度快,API 简单,适合大多数场景。
- xml.dom.minidom:标准库,内存高,速度慢,适合需要完整 DOM 树随机访问。
- BeautifulSoup:第三方,内存较高,速度中等,易用性极高,适合复杂或 HTML/XML 混合解析。
- lxml.etree:第三方,内存中等,速度最快,支持 XPath,适合性能敏感和高级查询。
- xml.sax:标准库,内存极低,速度较快,编码复杂,适合超大文件流式处理。

选型建议
日常脚本开发首选 xml.etree.ElementTree,零依赖且能满足大部分需求。当需要 XPath 或对性能有极致要求时,选用 lxml。处理不规范文档或需要强大查找能力时,BeautifulSoup 更加得心应手。如果 XML 文件大小超过数 GB,使用 xml.sax 避免内存溢出。仅当必须遵守 W3C DOM 规范或需要随机修改节点时,才考虑 minidom。
回复

使用道具 举报

发表于 1 小时前 | 显示全部楼层

Re: Python读取XML文件:5种方法代码对比与选择指南

感谢楼主的详细分享!这五种方法的对比非常实用,尤其是代码示例直接可以跑起来。 我用得比较多的是 ElementTree 和 lxml,平时小项目用 ElementTree 就够了,标准库省心。遇到大文件或需要 XPath 的时候,lxml 性能优势明显。楼主提到 BeautifulSoup 对格式不规范的 XML 容错性高,这点很关键,有时候从网上下载的 XML 文件确实会有点“脏”,用 BS 确实省事。 另外想问一下,如果是超大 XML 文件(比如几百 MB),楼主有没有试过用 iterparse 流式解析?虽然 lxml 也有 incremental parsing,但 ElementTree 的 iterparse 也能节省内存,能不能在文末补充一下这种场景的选型建议?
回复 支持 反对

使用道具 举报

发表于 1 小时前 | 显示全部楼层

Re: Python读取XML文件:5种方法代码对比与选择指南

总结得很清晰,正好最近在处理类似XML,平时习惯用ElementTree,标准库无依赖最省事。但遇到格式不太规范的XML时,BeautifulSoup真的能省不少力气,容错性确实比标准库好很多。楼主提到的三种方法基本覆盖了轻量、DOM、灵活三个方向,很实用。另外标题说是五种方法,后面是不是还有lxml和cElementTree的对比?如果方便的话,希望能补上大文件处理或性能方面的选型建议,谢谢分享!
回复 支持 反对

使用道具 举报

发表于 1 小时前 | 显示全部楼层

Re: Python读取XML文件:5种方法代码对比与选择指南

感谢楼主的详细对比!平时用得最多的是ElementTree,标准库确实方便,不过在处理超大文件时容易占内存。期待楼主把剩下两种也写完,特别是lxml,听说速度很快,不知道对示例里这种嵌套结构会不会有更好的表现?另外,如果XML文件格式稍微不规范,BeautifulSoup和minidom的容错性差别大吗?
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

指导单位

江苏省公安厅

江苏省通信管理局

浙江省台州刑侦支队

DEFCON GROUP 86025

Hacking Group 021A

旗下站点

态势感知中心

应急响应中心

红盟安全

联系我们

官方QQ群:112851260

官方邮箱:security#ihonker.org(#改成@)

官方核心成员

关注微信公众号

Archiver|手机版|小黑屋| ( 沪ICP备2021026908号 )

GMT+8, 2026-7-2 11:40 , Processed in 0.038626 second(s), 18 queries , Gzip On, Redis On.

Powered by ihonker.com

Copyright © 2015-现在.

  • 返回顶部