Mise à jour 2018:
En février 2018, l'utilisation de compressions comme celles-ci gzip
est devenue très populaire (environ 73% de tous les sites Web l'utilisent, y compris les grands sites comme Google, YouTube, Yahoo, Wikipedia, Reddit, Stack Overflow et Stack Exchange Network).
Si vous effectuez un décodage simple comme dans la réponse d'origine avec une réponse gzippée, vous obtiendrez une erreur similaire ou similaire à celle-ci:
UnicodeDecodeError: le codec 'utf8' ne peut pas décoder l'octet 0x8b en position 1: octet de code inattendu
Afin de décoder une réponse gzpipped, vous devez ajouter les modules suivants (en Python 3):
import gzip
import io
Remarque: dans Python 2, vous utiliseriez à la StringIO
place deio
Ensuite, vous pouvez analyser le contenu comme ceci:
response = urlopen("https://example.com/gzipped-ressource")
buffer = io.BytesIO(response.read())
gzipped_file = gzip.GzipFile(fileobj=buffer)
decoded = gzipped_file.read()
content = decoded.decode("utf-8")
Ce code lit la réponse et place les octets dans un tampon. Le gzip
module lit ensuite le tampon à l'aide de la GZipFile
fonction. Après cela, le fichier gzippé peut à nouveau être lu en octets et décodé en texte normalement lisible à la fin.
Réponse originale de 2010:
Pouvons-nous obtenir la valeur réelle utilisée link
?
De plus, nous rencontrons généralement ce problème ici lorsque nous essayons .encode()
une chaîne d'octets déjà codée. Vous pouvez donc essayer de le décoder d'abord comme dans
html = urllib.urlopen(link).read()
unicode_str = html.decode(<source encoding>)
encoded_str = unicode_str.encode("utf8")
Par exemple:
html = '\xa0'
encoded_str = html.encode("utf8")
Échoue avec
UnicodeDecodeError: 'ascii' codec can't decode byte 0xa0 in position 0: ordinal not in range(128)
Tandis que:
html = '\xa0'
decoded_str = html.decode("windows-1252")
encoded_str = decoded_str.encode("utf8")
Réussit sans erreur. Notez que "windows-1252" est quelque chose que j'ai utilisé comme exemple . J'ai eu ceci de chardet et il avait 0,5 confiance que c'était juste! (enfin, comme indiqué avec une chaîne de 1 caractère, à quoi vous attendez-vous?) Vous devriez changer cela pour l'encodage de la chaîne d'octets renvoyée par .urlopen().read()
ce qui s'applique au contenu que vous avez récupéré.
Un autre problème que je vois là-bas est que la .encode()
méthode de chaîne renvoie la chaîne modifiée et ne modifie pas la source en place. Il est donc inutile d'avoir self.response.out.write(html)
comme html n'est pas la chaîne encodée de html.encode (si c'est ce que vous visiez à l'origine).
Comme Ignacio l'a suggéré, vérifiez la page Web source pour le codage réel de la chaîne renvoyée de read()
. C'est soit dans l'une des balises Meta, soit dans l'en-tête ContentType de la réponse. Utilisez-le ensuite comme paramètre pour .decode()
.
Notez cependant qu'il ne faut pas supposer que les autres développeurs sont suffisamment responsables pour s'assurer que les déclarations d'en-tête et / ou de jeu de méta caractères correspondent au contenu réel. ( Ce qui est un PITA, ouais, je sais, je suis un de ceux avant).