You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用Python加速提取大型XML文件中的数据?

问题描述

我是Python新手,需要提取XML文件中的属性值。目前使用for循环从xml.dom.minidom.document中获取属性值,但文件包含50万条数据,处理耗时较长。尝试使用lxml时出现错误:module 'lxml' has no attribute 'parse' or 'Xpath',后续调用Xpath时触发AttributeError。

XML格式

<?xml version="1.0" encoding="utf-8"?>
<variable_output>
  <!--version      : 1-->
  <!--object title : Volume (1)-->
  <!--scalar variable : Temperature (TEMP)-->
  <POINT>
    <Vertex>
      <Position x="-0.176300004" y="-0.103100002" z="-0.153699994"/>
      <Scalar TEMP="84.192421"/>
    </Vertex>
  </POINT>
  <POINT>
    <Vertex>
      <Position x="-0.173557162" y="-0.103100002" z="-0.153699994"/>
      <Scalar TEMP="83.9050522"/>
    </Vertex>
  </POINT>
  <POINT>
    <Vertex>
      <Position x="-0.170814306" y="-0.103100002" z="-0.153699994"/>
      <Scalar TEMP="83.7506332"/>
    </Vertex>
  </POINT>
</variable_output>

使用的代码

from xml.dom.minidom import parse
import xml.dom.minidom
import csv
import pandas as pd
import numpy as np
import os
import glob
import time
from lxml import etree

v=[]

doc =parse("document.xml")
Val = doc.getElementsByTagName("Scalar")

t0 = time.time()
for s in Val:
    v=np.append(v,float(s.attributes['TEMP'].value))
res=np.array([v])
t1 = time.time()
total = (t1-t0)
print('Time for Value', str(total))

# Using lxml 
doc2=etree.parse("document.xml")
        
# try using Xpath
t0 = time.time()
temp=doc2.Xpath("/POINT/Vertex/Scaler/@TEMP")
t1 = time.time()
total2 = t1-t0
print('Time for Value', str(total2))

# save data as csv from xml
pd.DataFrame(res.T).to_csv(('Data.csv'),index=False,header=False)   #write timestep as csv

报错信息

In [12]: temp=doc2.Xpath("/POINT/Vertex/Scaler/@TEMP")
Traceback (most recent call last):

  File "<ipython-input-12-bbd832a3074e>", line 1, in <module>
    temp=doc2.Xpath("/POINT/Vertex/Scaler/@TEMP")

AttributeError: 'lxml.etree._ElementTree' object has no attribute 'Xpath'

需要解决lxml使用错误,并获得加速提取数据的方法。


解决方案

修复lxml使用错误

你的lxml代码存在三个关键错误:

  • 方法名大小写错误:lxml中XPath方法是小写的xpath(),不是大写的Xpath()
  • XPath路径错误:XML根节点是variable_output,路径需要从根开始,即/variable_output/POINT/Vertex/Scalar/@TEMP
  • 标签名拼写错误:XML中的标签是<Scalar>,你写成了Scaler

修复后的lxml代码片段:

from lxml import etree
import time
import numpy as np
import pandas as pd

t0 = time.time()
doc2 = etree.parse("document.xml")
# 修正后的XPath表达式和方法调用
temp = doc2.xpath("/variable_output/POINT/Vertex/Scalar/@TEMP")
# 转换为float数组
temp_values = np.array(temp, dtype=np.float64)
t1 = time.time()
print('Time for Value', t1 - t0)

# 保存到CSV
pd.DataFrame(temp_values).to_csv("Data_lxml.csv", index=False, header=False)

另外,你之前误以为lxml没有parse方法,是因为parse属于lxml.etree模块,你已经正确导入了from lxml import etree,所以etree.parse()是正确用法。

加速数据提取的优化方案

针对50万条数据的大XML文件,推荐以下优化方式:

1. 优化原minidom代码

原代码中循环使用np.append()会频繁重新分配内存,导致效率低下。改为先收集到Python列表,再一次性转换为numpy数组:

from xml.dom.minidom import parse
import time
import numpy as np

t0 = time.time()
doc = parse("document.xml")
Val = doc.getElementsByTagName("Scalar")

# 先收集到列表,避免频繁数组扩容
v = []
for s in Val:
    v.append(float(s.attributes['TEMP'].value))
res = np.array(v)
t1 = time.time()
print('Time for Value', t1 - t0)

2. 使用lxml流式解析(iterparse)

对于超大型XML文件,etree.parse()会把整个文档加载到内存,可能导致内存不足。使用etree.iterparse()流式处理,逐节点解析,内存占用更低:

from lxml import etree
import time
import numpy as np
import pandas as pd

t0 = time.time()
temp_values = []
# 流式解析,只关注Scalar标签
for event, elem in etree.iterparse("document.xml", events=('end',), tag='Scalar'):
    temp_values.append(float(elem.attrib['TEMP']))
    # 清理已处理的节点,释放内存
    elem.clear()
    while elem.getprevious() is not None:
        del elem.getparent()[0]

res = np.array(temp_values)
t1 = time.time()
print('Time for Value', t1 - t0)

pd.DataFrame(res).to_csv("Data_stream.csv", index=False, header=False)

3. 性能对比

  • 原minidom方法:最慢,且内存占用高
  • lxml xpath方法:比minidom快3-5倍,适合内存足够的场景
  • lxml iterparse流式方法:内存占用最低,速度接近xpath方法,适合超大型文件

内容的提问来源于stack exchange,提问作者Sanjeet Limbu

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.13 12:05:13