Aggiornamento 2018:
A partire da febbraio 2018, l'utilizzo di compressioni come gzip
è diventato abbastanza popolare (circa il 73% di tutti i siti Web lo utilizza, inclusi siti di grandi dimensioni come Google, YouTube, Yahoo, Wikipedia, Reddit, Stack Overflow e Stack Exchange Network).
Se esegui una decodifica semplice come nella risposta originale con una risposta compressa, otterrai un errore simile o simile a questo:
UnicodeDecodeError: il codec 'utf8' non può decodificare byte 0x8b in posizione 1: byte di codice imprevisto
Per decodificare una risposta gzpipped è necessario aggiungere i seguenti moduli (in Python 3):
import gzip
import io
Nota: in Python 2 useresti StringIO
invece diio
Quindi puoi analizzare il contenuto in questo modo:
response = urlopen("https://example.com/gzipped-ressource")
buffer = io.BytesIO(response.read()) # Use StringIO.StringIO(response.read()) in Python 2
gzipped_file = gzip.GzipFile(fileobj=buffer)
decoded = gzipped_file.read()
content = decoded.decode("utf-8") # Replace utf-8 with the source encoding of your requested resource
Questo codice legge la risposta e inserisce i byte in un buffer. Il gzip
modulo legge quindi il buffer utilizzando la GZipFile
funzione. Successivamente, il file gzipped può essere nuovamente letto in byte e decodificato alla fine in testo normalmente leggibile.
Risposta originale del 2010:
Possiamo ottenere il valore effettivo utilizzato per link
?
Inoltre, di solito incontriamo questo problema qui quando proviamo a .encode()
una stringa di byte già codificata. Quindi potresti provare a decodificarlo prima come in
html = urllib.urlopen(link).read()
unicode_str = html.decode(<source encoding>)
encoded_str = unicode_str.encode("utf8")
Come esempio:
html = '\xa0'
encoded_str = html.encode("utf8")
Non riesce con
UnicodeDecodeError: 'ascii' codec can't decode byte 0xa0 in position 0: ordinal not in range(128)
Mentre:
html = '\xa0'
decoded_str = html.decode("windows-1252")
encoded_str = decoded_str.encode("utf8")
Succede senza errori. Nota che "windows-1252" è qualcosa che ho usato come esempio . Ho preso questo da chardet e aveva la sicurezza di avere ragione! (bene, come indicato con una stringa di 1 carattere, cosa ti aspetti) Dovresti cambiarlo con la codifica della stringa di byte restituita da .urlopen().read()
ciò che si applica al contenuto che hai recuperato.
Un altro problema che vedo è che il .encode()
metodo string restituisce la stringa modificata e non modifica l'origine in atto. Quindi è un po 'inutile avere self.response.out.write(html)
come html non è la stringa codificata da html.encode (se è quello che stavi mirando originariamente).
Come suggerito da Ignacio, controlla la pagina web di origine per la codifica effettiva della stringa restituita da read()
. È in uno dei meta tag o nell'intestazione ContentType nella risposta. Usalo quindi come parametro per .decode()
.
Si noti tuttavia che non si deve presumere che altri sviluppatori siano abbastanza responsabili da assicurarsi che l'intestazione e / o le dichiarazioni del set di caratteri meta corrispondano al contenuto effettivo. (Che è una valle di lacrime, sì, dovrei so, io ero uno di quelli prima).