example - xml python 3
Analizar la alimentaciĆ³n xml comprimida en ElementTree (2)
Estoy tratando de analizar el siguiente feed en ElementTree en python: " http://smarkets.s3.amazonaws.com/oddsfeed.xml " (archivo grande de advertencia)
Esto es lo que he intentado hasta ahora:
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)
pero parece que se cuelga en compressed_data = feed.read()
, infinitamente tal vez? (Sé que es un archivo grande, pero parece demasiado largo en comparación con otros feeds no comprimidos que analicé, y este tamaño está matando cualquier ganancia de ancho de banda de la compresión gzip en primer lugar).
Luego probé las requests
, con
url = "http://smarkets.s3.amazonaws.com/oddsfeed.xml"
headers = {''accept-encoding'': ''gzip, deflate''}
r = requests.get(url, headers=headers, stream=True)
pero ahora
tree=ET.parse(r.content)
o
tree=ET.parse(r.text)
pero estos levantan excepciones.
¿Cuál es la forma correcta de hacer esto?
La función ET.parse
toma "un nombre de archivo o un objeto de archivo que contiene datos XML". Le estás dando una cadena llena de XML. Intentará abrir un archivo cuyo nombre es ese gran fragmento de XML. Probablemente no hay tal archivo.
Desea la función fromstring
o el constructor XML
.
O, si lo prefiere, ya tiene un objeto de archivo, gzipper
; podrías pasar eso para parse
lugar de leerlo en una cadena.
Todo esto está cubierto por el breve Tutorial en los documentos:
Podemos importar estos datos leyendo de un archivo:
import xml.etree.ElementTree as ET
tree = ET.parse(''country_data.xml'')
root = tree.getroot()
O directamente de una cadena:
root = ET.fromstring(country_data_as_string)
Puede pasar el valor devuelto por urlopen()
directamente a GzipFile()
y, a su vez, puede pasarlo a métodos iterparse()
como 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)
donde getelements()
permite analizar archivos que no caben en la memoria.
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
Para preservar la memoria, el árbol xml construido se borra en cada elemento de etiqueta .