| You are here: Inicio > Inmersión en Python > Servicios Web HTTP > Tratamiento de datos comprimidos | << >> | ||||
Inmersión en PythonPython de novato a experto |
|||||
La última característica importante de HTTP que queremos tratar es la compresión. Muchos servicios web tienen la capacidad de enviar los datos comprimidos, lo que puede rebajar en un 60% o más la cantidad de datos a enviar. Esto se aplica especialmente a los servicios web XML, ya que los datos XML se comprimen bastante bien.
Los servidores no nos van a dar comprimidos los datos a menos que le digamos que lo aceptamos así.
>>> import urllib2, httplib >>> httplib.HTTPConnection.debuglevel = 1 >>> request = urllib2.Request('http://diveintomark.org/xml/atom.xml') >>> request.add_header('Accept-encoding', 'gzip')>>> opener = urllib2.build_opener() >>> f = opener.open(request) connect: (diveintomark.org, 80) send: ' GET /xml/atom.xml HTTP/1.0 Host: diveintomark.org User-agent: Python-urllib/2.1 Accept-encoding: gzip
' reply: 'HTTP/1.1 200 OK\r\n' header: Date: Thu, 15 Apr 2004 22:24:39 GMT header: Server: Apache/2.0.49 (Debian GNU/Linux) header: Last-Modified: Thu, 15 Apr 2004 19:45:21 GMT header: ETag: "e842a-3e53-55d97640" header: Accept-Ranges: bytes header: Vary: Accept-Encoding header: Content-Encoding: gzip
header: Content-Length: 6289
header: Connection: close header: Content-Type: application/atom+xml
>>> compresseddata = f.read()>>> len(compresseddata) 6289 >>> import StringIO >>> compressedstream = StringIO.StringIO(compresseddata)
>>> import gzip >>> gzipper = gzip.GzipFile(fileobj=compressedstream)
>>> data = gzipper.read()
>>> print data
<?xml version="1.0" encoding="iso-8859-1"?> <feed version="0.3" xmlns="http://purl.org/atom/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xml:lang="en"> <title mode="escaped">dive into mark</title> <link rel="alternate" type="text/html" href="http://diveintomark.org/"/> <-- rest of feed omitted for brevity --> >>> len(data) 15955
| Continuamos el ejemplo anterior, y f es el objeto de tipo fichero devuelto por el abridor de URL. Normalmente obtendríamos datos sin comprimir usando su método read(), pero dado que estos datos han sido comprimidos, éste sólo es el primer paso para obtener los datos que realmente queremos. | |
| Bien, este paso es un rodeo un poco sucio. Python tiene un módulo gzip que lee (y escribe) ficheros comprimidos en el disco. Pero no tenemos un fichero sino un búfer en memoria comprimido con gzip, y no queremos escribirlo en un fichero temporal sólo para poder descomprimirlo. Así que lo que haremos es crear un objeto de tipo fichero partiendo de los datos en memoria (compresseddata), haciendo uso del módulo StringIO. Conocimos este módulo en el capítulo anterior, pero ahora le hemos encontrado un nuevo uso. | |
| Ahora podemos crear una instancia de GzipFile y decirle que su “fichero” es el objeto tipo fichero compressedstream. | |
| Ésta es la línea que hace todo el trabajo: “leer” de GzipFile descomprimirá los datos. ¿Extraño? Sí, pero tiene sentido de una manera retorcida. gzipper es un objeto de tipo fichero que representa un fichero comprimido con gzip. Ese “fichero” no es real, sin embargo; en realidad gzipper sólo está “leyendo” del objeto tipo fichero que creamos con StringIO para obtener los datos comprimidos, que están en memoria en la variable compresseddata. ¿Y de dónde vinieron esos datos comprimidos? Originalmente los descargamos de un servidor HTTP remoto “leyendo” el objeto tipo fichero que construimos con urllib2.build_opener. Y sorprendentemente, todo funciona. Cada paso en la cadena ignora que el paso anterior está engañándole. | |
| ¡Mira mamá!, datos de verdad (15955 bytes, para ser exactos). |
“¡Pero espere!” puedo oírle gritar. “¡Esto podría ser incluso más sencillo!” Sé lo que está pensando. Está pensando que opener.open devuelve un fichero de tipo objeto así que, ¿por qué no eliminar el paso intermedio por StringIO y limitarnos a pasar f directamente a GzipFile? Bueno vale, quizá no estuviera pensando eso, pero no se preocupe que tampoco hubiera funcionado.
>>> f = opener.open(request)>>> f.headers.get('Content-Encoding')
'gzip' >>> data = gzip.GzipFile(fileobj=f).read()
Traceback (most recent call last): File "<stdin>", line 1, in ? File "c:\python23\lib\gzip.py", line 217, in read self._read(readsize) File "c:\python23\lib\gzip.py", line 252, in _read pos = self.fileobj.tell() # Save current position AttributeError: addinfourl instance has no attribute 'tell'
<< Manejo de redirecciones |
| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | |
Todo junto >> |