【问题标题】:How to extract very large xml data and store in a dictionary in python如何提取非常大的xml数据并存储在python中的字典中
【发布时间】:2020-08-18 17:15:36
【问题描述】:

我有一个名为 Comments.xml 的 XML 文件,其大小为 15 GB。我想获得一个有 2 个键的字典,即 UserId 和 Text。请注意,文件中有许多UserId 和Text 的缺失值。我尝试了以下代码,但由于文件大小太大导致 RAM(13 GB RAM)崩溃。有没有一种高效的方法可以从xml文件中获取数据进行数据分析?

部分xml文件Comments.xml

<comments>
<row Id = '1' UserId = '143' Text = 'Hello World'>
<row Id = '2' UserId = '183' Text = 'Trigonometry is important.'>
<row Id = '3' UserId = '5645' Text = 'Mathematics is best.'>
<row Id = '4' UserId = '143' Text = 'Hello stack overflow'>
<row Id = '5' UserId = '143' Text = 'Hello'>

代码

import xml.etree.cElementTree as ET

tree = ET.iterparse('Comments.xml')

comments = {} #Dictionary to store the required data

for event, root in tree:

  if (('Text' in root.attrib) and ('UserId' in root.attrib)): #To check for missing values
    Text = root.attrib['Text']
    UserId = root.attrib['UserId']
    userid_comments.update({UserId:Text}) #Adding data to dictionary
    root.clear()

预期输出

{'143':'Hello World','183':'Trigonometry is important.','5645':'Mathematics is best.','143':'Hello stack overflow','143':'Hello'}

OR

{'UserId':['143','183','5645','143','143'],'Text':['Hello World','Trigonometry is important.','Mathematics is best.','Hello stack overflow','Hello']}

【问题讨论】:

  • 您的代码得到的输出是什么?它与预期输出有何不同?
  • 而且您发布的 xml 无效row 标签未结束
  • 你熟悉generators吗?
  • 字典没有重复键。您的预期输出无效
  • @deadshot 我已经添加了预期的输出,您可以帮助我提供您认为对数据分析更有用的任何输出。此外,我刚刚显示了 xml 文件的前 5 行,所以我没有关闭根标记。原始 xml 文件有效,此代码适用于较小的 xml 文件。

标签: python python-3.x xml dictionary xml-parsing


【解决方案1】:

见下文。

这不会解决您的 RAM 问题。为了解决 RAM 问题,您需要使用 SAX:

Simple API for XML (SAX) - 在这里,您为感兴趣的事件注册回调,然后让解析器继续处理文档。当您的文档很大或您有内存限制时,这很有用,它会在从磁盘读取文件时解析文件,并且整个文件永远不会存储在内存中。

import xml.etree.ElementTree as ET
from collections import defaultdict

data = defaultdict(list)

xml = '''<comments>
<row Id = "1" UserId = "143" Text = "Hello World"/>
<row Id = "2" UserId = "183" Text = "Trigonometry is important."/>
<row Id = "3" UserId = "5645" Text = "Mathematics is best."/>
<row Id = "4" UserId = "143" Text = "Hello stack overflow"/>
<row Id = "5" UserId = "143" Text = "Hello"/></comments>'''

root = ET.fromstring(xml)
for row in root.findall('.//row'):
    user_id = row.attrib.get('UserId')
    text = row.attrib.get('Text')
    if user_id is not None and text is not None:
        data[user_id].append(text)
print(data)

输出

defaultdict(<class 'list'>, {'143': ['Hello World', 'Hello stack overflow', 'Hello'], '183': ['Trigonometry is important.'], '5645': ['Mathematics is best.']})

【讨论】:

    【解决方案2】:

    另一种方法。

    import io
    from simplified_scrapy import SimplifiedDoc
    
    def getComments(fileName):
        comments = {'UserId': [], 'Text': []}
        with io.open(fileName, "r", encoding='utf-8') as file:
            line = file.readline()  # Read data line by line
            while line != '':
                doc = SimplifiedDoc(line)  # Instantiate a doc
                row = doc.getElement('row')  # Get row
                if row:
                    comments['UserId'].append(row['UserId'])
                    comments['Text'].append(row['Text'])
                line = file.readline()
        return comments
    comments = getComments('Comments.xml')  # This dictionary will be very large, too
    

    这里有更多示例:https://github.com/yiyedata/simplified-scrapy-demo/tree/master/doc_examples

    【讨论】:

      猜你喜欢
      • 2017-04-08
      • 1970-01-01
      • 2023-04-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-09-19
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多