Atualização de 2018:
A partir de fevereiro de 2018, o uso de compressões como gzip
se tornou bastante popular (cerca de 73% de todos os sites usam, incluindo sites grandes como Google, YouTube, Yahoo, Wikipedia, Reddit, Stack Overflow e Stack Exchange Network).
Se você fizer uma decodificação simples, como na resposta original, com uma resposta compactada com gzip, receberá um erro semelhante ou semelhante a este:
UnicodeDecodeError: o codec 'utf8' não pode decodificar o byte 0x8b na posição 1: byte de código inesperado
Para decodificar uma resposta gzpipped, você precisa adicionar os seguintes módulos (no Python 3):
import gzip
import io
Nota: No Python 2 você usaria em StringIO
vez deio
Em seguida, você pode analisar o conteúdo da seguinte maneira:
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
Este código lê a resposta e coloca os bytes em um buffer. O gzip
módulo lê o buffer usando a GZipFile
função Depois disso, o arquivo compactado com gzip pode ser lido em bytes novamente e decodificado para texto normalmente legível no final.
Resposta original de 2010:
Podemos obter o valor real usado link
?
Além disso, geralmente encontramos esse problema aqui quando estamos tentando .encode()
uma sequência de bytes já codificada. Portanto, você pode tentar decodificá-lo primeiro, como em
html = urllib.urlopen(link).read()
unicode_str = html.decode(<source encoding>)
encoded_str = unicode_str.encode("utf8")
Como um exemplo:
html = '\xa0'
encoded_str = html.encode("utf8")
Falha com
UnicodeDecodeError: 'ascii' codec can't decode byte 0xa0 in position 0: ordinal not in range(128)
Enquanto:
html = '\xa0'
decoded_str = html.decode("windows-1252")
encoded_str = decoded_str.encode("utf8")
Sucesso sem erro. Observe que "windows-1252" é algo que usei como exemplo . Eu peguei isso do chardet e tinha 0,5 confiança de que está certo! (bem, como fornecido com uma cadeia de caracteres de 1 caractere, o que você espera) Você deve alterar isso para a codificação da cadeia de bytes retornada .urlopen().read()
para a que se aplica ao conteúdo recuperado.
Outro problema que vejo é que o .encode()
método string retorna a string modificada e não modifica a fonte no local. Portanto, é meio inútil ter, self.response.out.write(html)
pois html não é a sequência codificada de html.encode (se é isso que você estava originalmente buscando).
Como Ignacio sugeriu, verifique na página de origem a codificação real da string retornada read()
. Está em uma das metatags ou no cabeçalho ContentType na resposta. Use isso então como o parâmetro para .decode()
.
Observe, no entanto, que não se deve presumir que outros desenvolvedores sejam responsáveis o suficiente para garantir que o cabeçalho e / ou as declarações do conjunto de meta caracteres correspondam ao conteúdo real. (Que é uma PITA, sim, eu deveria saber, eu era uma dessas antes).