脚本专家 发表于 2026-7-2 10:00:01

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

Python 提供了多种读取 XML 文件的库,从标准库中的 xml.etree.ElementTree 到第三方的高性能 lxml,各有适用场景。本文以一份包含国家信息的 test.xml 为例,演示五种主流方法的核心用法,并给出选型建议。

示例 XML 文件(test.xml)内容如下:

<?xml version="1.0"?>
<data>
<country name="Liechtenstein">
    <rank>1</rank>
    <year>2008</year>
    <gdppc>141100</gdppc>
    <neighbor name="Austria" direction="E"/>
    <neighbor name="Switzerland" direction="W"/>
</country>
<country name="Singapore">
    <rank>4</rank>
    <year>2011</year>
    <gdppc>59900</gdppc>
    <neighbor name="Malaysia" direction="N"/>
</country>
</data>


方法一:xml.etree.ElementTree(标准库,轻量级)
ElementTree 是 Python 官方推荐的标准库模块,API 简洁,无需安装第三方包。它支持从文件路径或字符串解析,并提供 find/findall/iter 等便捷方法。

import xml.etree.ElementTree as ET

# 解析文件
tree = ET.parse('test.xml')
root = tree.getroot()
# 解析字符串:ET.fromstring(xml_string)

print(f"根节点标签: {root.tag}")
for child in root:
    print(f"子节点: {child.tag}, 属性: {child.attrib}")
    for subchild in child:
      print(f"孙节点: {subchild.tag}, 文本: {subchild.text}")

# findall 与 get 用法
for country in root.findall('country'):
    name = country.get('name')
    rank = country.find('rank').text
    print(f"国家: {name}, 排名: {rank}")

# iter 迭代查找特定标签
for neighbor in root.iter('neighbor'):
    print(f"邻居: {neighbor.get('name')}, 方向: {neighbor.get('direction')}")


方法二:xml.dom.minidom(标准库,完整 DOM)
minidom 实现了 W3C DOM 接口,将整个文档加载为内存树,适合需要随机访问或修改节点的场景。但内存占用较高,速度较慢。

from xml.dom import minidom

dom = minidom.parse('test.xml')
root = dom.documentElement

countries = root.getElementsByTagName('country')
print(f"找到 {len(countries)} 个国家")
for country in countries:
    name = country.getAttribute('name')
    print(f"国家: {name}")
    rank = country.getElementsByTagName('rank').firstChild.data
    year = country.getElementsByTagName('year').firstChild.data
    print(f"排名: {rank}, 年份: {year}")
    for neighbor in country.getElementsByTagName('neighbor'):
      print(f"邻居: {neighbor.getAttribute('name')}, 方向: {neighbor.getAttribute('direction')}")


方法三:BeautifulSoup(第三方库,灵活强大)
BeautifulSoup 原本用于 HTML 解析,但指定 XML 解析器后可完美处理 XML。安装命令:pip install beautifulsoup4,并需额外安装解析器(如 lxml-xml)。它支持 find_all、CSS 选择器,对格式不规范的文档容错性高。

from bs4 import BeautifulSoup

with open('test.xml', 'r', encoding='utf-8') as f:
    soup = BeautifulSoup(f, 'xml')# 或 'lxml-xml'

print(f"根节点: {soup.data.name}")
countries = soup.find_all('country')
for country in countries:
    print(f"国家: {country['name']}")
    print(f"排名: {country.rank.text}, 年份: {country.year.text}")
    for neighbor in country.find_all('neighbor'):
      print(f"邻居: {neighbor['name']}, 方向: {neighbor['direction']}")
# CSS 选择器
for gdppc in soup.select('gdppc'):
    print(f"人均GDP: {gdppc.text}")


方法四:lxml.etree(第三方库,高性能)
lxml 在底层使用 C 扩展,速度极快,且完全兼容 ElementTree 的 API,同时支持 XPath 等高级查询。安装:pip install lxml。

from lxml import etree

tree = etree.parse('test.xml')
root = tree.getroot()
print(f"根节点: {root.tag}")
for country in root:
    print(f"国家属性: {country.attrib}")

# XPath 查找所有 rank
ranks = root.xpath('//rank')
print("所有排名:")
for rank in ranks:
    print(f"{rank.text}")

# XPath 查找指定国家年份
singapore_year = root.xpath('//country[@name="Singapore"]/year/text()')
print(f"Singapore 年份: {singapore_year}")

# XPath 获取所有 neighbor 的 direction 属性
directions = root.xpath('//neighbor/@direction')
print(f"所有方向: {directions}")


方法五:xml.sax(标准库,流式解析)
SAX(Simple API for XML)基于事件驱动,边读边解析,内存占用极低,适合处理超大型 XML 文件。但其代码编写相对繁琐,需要自定义 ContentHandler。

import xml.sax

class CountryHandler(xml.sax.ContentHandler):
    def __init__(self):
      self.current_data = ""
      self.name = ""
      self.rank = ""

    def startElement(self, tag, attributes):
      self.current_data = tag
      if tag == "country":
            self.name = attributes["name"]
            print(f"\n国家: {self.name}")
      elif tag == "neighbor":
            print(f"邻居: {attributes['name']}, 方向: {attributes['direction']}")

    def characters(self, content):
      if self.current_data == "rank":
            self.rank = content
      elif self.current_data == "year":
            self.year = content

    def endElement(self, tag):
      if self.current_data == "rank":
            print(f"排名: {self.rank}")
      elif self.current_data == "year":
            print(f"年份: {self.year}")
      self.current_data = ""

parser = xml.sax.make_parser()
parser.setFeature(xml.sax.handler.feature_namespaces, 0)
handler = CountryHandler()
parser.setContentHandler(handler)
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。

热心网友7 发表于 2026-7-2 10:10:00

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

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

热心网友7 发表于 2026-7-2 10:10:00

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

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

热心网友7 发表于 2026-7-2 10:10:00

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

感谢楼主的详细对比!平时用得最多的是ElementTree,标准库确实方便,不过在处理超大文件时容易占内存。期待楼主把剩下两种也写完,特别是lxml,听说速度很快,不知道对示例里这种嵌套结构会不会有更好的表现?另外,如果XML文件格式稍微不规范,BeautifulSoup和minidom的容错性差别大吗?
页: [1]
查看完整版本: Python读取XML文件:5种方法代码对比与选择指南