web-dev-qa-db-fra.com

Est-ce que python urllib2 décompresse automatiquement les données gzip extraites de la page Web?

J'utilise 

 data=urllib2.urlopen(url).read()

Je veux savoir:

  1. Comment puis-je savoir si les données d'une URL sont gzippées?

  2. Est-ce que urllib2 décompresse automatiquement les données si elles sont gzippées? Les données seront-elles toujours une chaîne?

67
mlzboy
  1. Comment puis-je savoir si les données d'une URL sont gzippées?

Ceci vérifie si le contenu est compressé et le décompresse:

from StringIO import StringIO
import gzip

request = urllib2.Request('http://example.com/')
request.add_header('Accept-encoding', 'gzip')
response = urllib2.urlopen(request)
if response.info().get('Content-Encoding') == 'gzip':
    buf = StringIO(response.read())
    f = gzip.GzipFile(fileobj=buf)
    data = f.read()
  1. Est-ce que urllib2 décompresse automatiquement les données si elles sont gzippées? Les données seront-elles toujours une chaîne?

Non. Urllib2 ne décompresse pas automatiquement les données car l'en-tête 'Accept-Encoding' n'est pas défini par urllib2 mais par vous-même avec: request.add_header('Accept-Encoding','gzip, deflate')

143
ars

Si vous parlez d'un simple fichier .gz, non, urllib2 ne le décodera pas, vous obtiendrez le fichier inchangé .gz en sortie.

Si vous parlez de compression automatique au niveau HTTP avec Content-Encoding: gzip ou deflate, le client doit le demander délibérément à l'aide d'un en-tête Accept-Encoding.

urllib2 ne définit pas cet en-tête, donc la réponse qu'il reçoit ne sera pas compressée. Vous pouvez récupérer la ressource en toute sécurité sans avoir à vous soucier de la compression (bien que la compression n'étant pas prise en charge, la demande peut durer plus longtemps).

7
bobince

Nous avons répondu à votre question, mais pour une implémentation plus complète, jetez un oeil à l'implémentation de Mark Pilgrim dans ce , elle couvre le traitement des URL gzip, deflate, safe et bien plus encore, pour un analyseur RSS largement utilisé, mais néanmoins une référence utile.

5
RuiDC

Il semble que urllib3 gère cela automatiquement maintenant. 

En-têtes de référence: 

HTTPHeaderDict ({'ETag': '"112d13e-574c64196bcd9-gzip"', 'Vary': 'Accept-Encoding', 'Content-Encoding': 'gzip', 'X-Frame-Options': 'sameorigin', 'Serveur': 'Apache', 'Dernière modification': 'Sam, 01 sept. 2018 02:42:16 GMT', 'Options X-Content-Type-Type': 'nosniff', 'X-XSS-Protection': '1; mode = bloc', 'Content-Type': 'text/plain; Charset = utf-8', 'Strict-Transport-Security': 'max -age = 315360000; includeSubDomains ',' Compatible X-UA ':' IE = Edge ',' Date ':' Sam, 01 sept 2018 14h20:16 GMT ',' Accept-Ranges ':' octets ',' Transfer-Encoding ': ' chunked '}) 

Code de référence: 

import gzip
import io
import urllib3

class EDDBMultiDataFetcher():
    def __init__(self):
        self.files_dict = {
            'Populated Systems':'http://eddb.io/archive/v5/systems_populated.jsonl',
            'Stations':'http://eddb.io/archive/v5/stations.jsonl',
            'Minor factions':'http://eddb.io/archive/v5/factions.jsonl',
            'Commodities':'http://eddb.io/archive/v5/commodities.json'
            }
        self.http = urllib3.PoolManager()
    def fetch_all(self):
        for item, url in self.files_dict.items():
            self.fetch(item, url)

    def fetch(self, item, url, save_file = None):
        print("Fetching: " + item)
        request = self.http.request(
            'GET',
            url,
            headers={
                'Accept-encoding': 'gzip, deflate, sdch'
                })
        data = request.data.decode('utf-8')
        print("Fetch complete")
        print(data)
        print(request.headers)
        quit()


if __== '__main__':
    print("Fetching files from eddb.io")
    fetcher = EDDBMultiDataFetcher()
    fetcher.fetch_all()
0
RobotHumans