我正在尝试将以下Feed解析为python中的ElementTree:“http://smarkets.s3.amazonaws.com/oddsfeed.xml”(警告大文件)
这是我到目前为止所尝试的内容:
feed = urllib.urlopen("http://smarkets.s3.amazonaws.com/oddsfeed.xml")
# feed is compressed
compressed_data = feed.read()
import StringIO
compressedstream = StringIO.StringIO(compressed_data)
import gzip
gzipper = gzip.GzipFile(fileobj=compressedstream)
data = gzipper.read()
# Parse XML
tree = ET.parse(data)
但似乎只是挂在compressed_data = feed.read()
上,无限可能? (我知道这是一个很大的文件,但与我解析的其他非压缩的feed相比似乎太长了,而且这个大的数据首先会从gzip压缩中获得任何带宽增益)。
接下来,我尝试了requests
,
url = "http://smarkets.s3.amazonaws.com/oddsfeed.xml"
headers = {'accept-encoding': 'gzip, deflate'}
r = requests.get(url, headers=headers, stream=True)
但现在
tree=ET.parse(r.content)
或
tree=ET.parse(r.text)
但这会引发例外。
这样做的正确方法是什么?
答案 0 :(得分:5)
您可以将urlopen()
返回的值直接传递给GzipFile()
,然后您可以将其传递给ElementTree
方法,例如iterparse()
:
#!/usr/bin/env python3
import xml.etree.ElementTree as etree
from gzip import GzipFile
from urllib.request import urlopen, Request
with urlopen(Request("http://smarkets.s3.amazonaws.com/oddsfeed.xml",
headers={"Accept-Encoding": "gzip"})) as response, \
GzipFile(fileobj=response) as xml_file:
for elem in getelements(xml_file, 'interesting_tag'):
process(elem)
其中getelements()
允许解析不适合内存的文件。
def getelements(filename_or_file, tag):
"""Yield *tag* elements from *filename_or_file* xml incrementaly."""
context = iter(etree.iterparse(filename_or_file, events=('start', 'end')))
_, root = next(context) # get root element
for event, elem in context:
if event == 'end' and elem.tag == tag:
yield elem
root.clear() # free memory
为了保留内存,在每个标记元素上清除构造的xml树。
答案 1 :(得分:2)
ET.parse
函数采用“包含XML数据的文件名或文件对象”。你给它一个充满XML的字符串。它将尝试打开一个名为XML大块的文件。可能没有这样的文件。
您需要fromstring
函数或XML
构造函数。
或者,如果您愿意,您已经有了一个文件对象gzipper
;您可以将其传递给parse
,而不是将其读入字符串。
这些都由文档中的简短Tutorial涵盖:
我们可以通过从文件中读取来导入此数据:
import xml.etree.ElementTree as ET
tree = ET.parse('country_data.xml')
root = tree.getroot()
或直接来自字符串:
root = ET.fromstring(country_data_as_string)