You are here: Sommaire > Plongez au coeur de Python > Services Web HTTP > Prise en charge des données compressées. | << >> | ||||
Plongez au coeur de PythonDe débutant à expert |
La dernière fonctionnalité importante du protocole HTTP que nous voulons supporter est la compression. Beaucoup de services Web ont la capacité d'envoyer les données compressées, ce qui qui peut réduire le volume de données envoyées de 60 % ou plus. C'est particulièrement vrai des services Web XML puisque les données XML se compressent très bien.
Les serveurs n'envoient de données compressées que si on déclare les prendre en charge.
>>> 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
Nous continuons l'exemple précédent, f est l'objet-fichier retourné par l'opener d'URL. Appeler sa méthode read() nous permettrait d'habitude d'obtenir les données non compressées, mais ici ce n'est que la première étape puisque les données sont compressées par gzip. | |
Cette étape est un peu du bidouillage. Python a un module gzip qui lit (et peut aussi écrire) des fichiers compressés par gzip sur le disque. Mais ici, nous n'avons pas de fichier sur le disque, nous avons un tampon de données compressées en mémoire et nous n'allons pas l'écrire dans un fichier temporaire uniquement pour le décompresser. Donc nous créons un objet-fichier à partir de ces données en mémoire (compresseddata) à l'aide du module StringIO. Nous avons vu le module StringIO au chapitre précédent, mais nous avons maintenant un autre emploi pour lui. | |
Maintenant nous pouvons créer une instance de GzipFile et lui indiquer que son «fichier» est l'objet-fichier compressedstream. | |
Voici la ligne qui effectue le véritable travail : «lire» GzipFile décompresse les données. C'est étrange, mais en fait il y a une logique. gzipper est un objet-fichier qui repreésente un fichier compressé par gzip. Mais ce «fichier» n'est pas un vrai fichier sur le disque, gzipper ne «lit» que l'objet-fichier que nous avons créé avec StringIO pour contenir les données compressées, qui sont elles-mêmes en mémoire dans la variable compresseddata. Et d'où viennent les données compressées ? Nous les avons téléchargées d'un serveur HTTP distant en «lisant» l'objet-fichier que nous avions construit avec urllib2.build_opener. Et tout cela fonctionne, chaque étape dans la chaîne n'a aucune idée que l'étape précédente ne produit pas un vrai fichier. | |
Et voilà, de véritables données (15955 octets, plus précisément). |
«Mais attendez !», vous exclamez-vous. «Cela pourrait être simplifié !» Je sais ce que vous pensez, vous vous dite que opener.open retourne un objet-fichier, alors pourquoi ne pas se débarasser de l'intermédiaire StringIO et passer f directement à GzipFile ? Bon, peut-être que vous ne pensiez pas ça, mais de toute manière ça ne marche pas.
>>> 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'
<< Prise en charge des redirections. |
| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | |
Assembler les pièces >> |