【问题标题】:Parse multiple large XML files and write to CSV解析多个大型 XML 文件并写入 CSV
【发布时间】:2020-01-09 21:32:17
【问题描述】:

我有大约 1000 个 XML 文件,每个文件大小为 250 MB。我需要从中提取一些数据并写入 CSV。 不能有任何重复的条目。

我有一个配备 4GB RAM 和 AMD A8 处理器的系统。

我已经在这里浏览了一些以前的帖子,但他们似乎没有回答我的问题。

我已经用 Python 编写了代码,并在一个示例 XML 上对其进行了测试,它运行良好。

但是当我在所有文件上使用它并且不得不中途终止进程时,它非常慢(每个文件几乎 15 分钟)。

加快流程的最佳解决方案是什么?

这是代码

path='data/*.xml'
t=[]
for fname in glob.glob(path):
    print('Parsing ',fname)
    tree=ET.parse(fname)
    root=tree.getroot()
    x=root.findall('//Article/AuthorList//Author')
    for child in x:
        try:
            lastName=child.find('LastName').text
        except AttributeError:
            lastName=''
        try:
            foreName=child.find('ForeName').text
        except AttributeError:
            foreName=''
        t.append((lastName,foreName))
    print('Parsed ',fname)

t=set(t)

我想要最快的方法来获取条目没有任何重复值。 (也许存储在某个数据库中而不是变量 t 中,由于更多的空闲 RAM,将每个条目存储在数据库中会加快速度吗?-无论我需要哪种方法)

【问题讨论】:

  • 对于速度问题检查这个答案:stackoverflow.com/questions/18507481/…
  • 如果您想要唯一的条目,请使用集合或字典而不是列表。您是否尝试过 lxml,因为它可能会更快?

标签: python xml python-3.x csv


【解决方案1】:

不要将结果写入 Python 列表,而是创建一个带有UNIQUE 约束的数据库表,并将所有结果写入该表。完成所有写入后,将 DB 表转储为 csv。

如果您不希望有任何额外的依赖项来写入数据库,我建议您使用sqlite3,因为它在任何最近的 Python 安装中都是开箱即用的。

下面是一些开始使用的代码:

import sqlite3
conn = sqlite3.connect('large_xml.db')  # db will be created
cur = conn.cursor()
crt = "CREATE TABLE foo(fname VARCHAR(20), lname VARCHAR(20), UNIQUE(fname, lname))"
cur.execute(crt)
conn.commit()

path='data/*.xml'
for fname in glob.glob(path):
    print('Parsing ',fname)
    tree=ET.parse(fname)
    root=tree.getroot()
    x=root.findall('//Article/AuthorList//Author')
    count = 0
    for child in x:
        try:
            lastName=child.find('LastName').text
        except AttributeError:
            lastName=''
        try:
            foreName=child.find('ForeName').text
        except AttributeError:
            foreName=''
        cur.execute("INSERT OR IGNORE INTO foo(fname, lname) VALUES(?, ?)", (foreName, lastName))
        count += 1
        if count > 3000:  # commit every 3000 entries, you can tune this
            count = 0
            conn.commit()

    print('Parsed ',fname)

填充数据库后,将其转储到 csv,如下所示:

sqlite3 -header -csv large_xml.db "select * from foo;" > dump.csv

另外,尝试更快的解析方式。 此外,如果.text 属性在大多数情况下都可用, 以下可能会比异常处理更快:

lastName = getattr(child.find('LastName'), 'text', '')

【讨论】:

  • 好的,我会试试这个,然后回复评论。让我们希望它有效。
  • @SayangdiptoChakraborty 也许上面的一些入门代码可能会有所帮助。
  • 此代码将重复条目插入到表中。我明确提到我不想要任何重复的条目.. @Sam
  • 我希望 lastName, foreName 一起成为 UNIQUE 属性,而不是分开。也就是说,Michael, S 和 Michael, S 将被同等对待,而 Michael, K 和 Michael, S 将被区别对待。知道怎么做吗?
  • @SamChats 我已经做到了。刚刚添加了 PRIMARY KEY (LastName,ForeName) 谢谢没有太多关于 SQL 的知识很抱歉打扰。
猜你喜欢
  • 2015-05-24
  • 1970-01-01
  • 1970-01-01
  • 2015-05-25
  • 1970-01-01
  • 2021-12-07
  • 1970-01-01
  • 2015-05-14
  • 2011-05-09
相关资源
最近更新 更多