Подтвердить что ты не робот

Анализ сжатого XML-потока в ElementTree

Я пытаюсь проанализировать следующий поток в ElementTree в python: " 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(), бесконечно, может быть? (Я знаю, что это большой файл, но кажется слишком длинным по сравнению с другими не сжатыми фидами, которые я анализировал, и это большое количество убивает любые выгоды от сжатия от сжатия 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)

но они вызывают исключения.

Каков правильный способ сделать это?

4b9b3361

Ответ 1

Функция 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)

Ответ 2

Вы можете передать значение, возвращаемое 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 очищается для каждого элемента тега.