O objeto 'str' não possui atributo 'decodificar'. Erro no Python 3?

182

Aqui está o meu código:

import imaplib
from email.parser import HeaderParser

conn = imaplib.IMAP4_SSL('imap.gmail.com')
conn.login('[email protected]', 'password')
conn.select()
conn.search(None, 'ALL')
data = conn.fetch('1', '(BODY[HEADER])')
header_data = data[1][0][1].decode('utf-8')

Neste ponto, recebo a mensagem de erro

AttributeError: 'str' object has no attribute 'decode'

Python 3 não tem mais decodificação, estou certo? Como posso consertar isso?

Também em:

data = conn.fetch('1', '(BODY[HEADER])')

Estou selecionando apenas o 1º email. Como seleciono tudo?

Martijn Pieters
fonte

Respostas:

181

Você está tentando decodificar um objeto que está decodificado . Você tem um str, não há mais necessidade de decodificação do UTF-8.

Simplesmente largue a .decode('utf-8')peça:

header_data = data[1][0][1]

Quanto à sua fetch()ligação, você está pedindo explicitamente apenas a primeira mensagem. Use um intervalo se desejar recuperar mais mensagens. Veja a documentação :

As opções message_set para os comandos abaixo são uma sequência que especifica uma ou mais mensagens a serem executadas. Pode ser um número de mensagem simples ( '1'), um intervalo de números de mensagens ( '2:4') ou um grupo de intervalos não contíguos separados por vírgulas ( '1:3,6:9'). Um intervalo pode conter um asterisco para indicar um limite superior infinito ( '3:*').

Martijn Pieters
fonte
6
Existe uma maneira simples de fazer isso condicionalmente? (Eu só quero decodificar se a mensagem é codificada.)
devinbost
5
@devinbost: em Python 3? Teste o tipo de objeto ou o decodeatributo ou apenas pegue a exceção. try: data = data.decode('...') except AttributeError: pass.
Martijn Pieters
2
@devinbost: no entanto, geralmente é melhor decodificar mais perto da fonte de seus dados, onde geralmente você sabe exatamente o que tem.
Martijn Pieters
37

Comece com o Python 3, toda a string é um objeto unicode.

  a = 'Happy New Year' # Python 3
  b = unicode('Happy New Year') # Python 2

o código anterior é o mesmo. Então eu acho que você deve remover o .decode('utf-8'). Porque você já recebeu o objeto unicode.

Neo Ko
fonte
37

Use-o por este método:

str.encode().decode()
Alireza
fonte
1
bytearray(str, 'encoding').decode('another_encoding')iria fazer o trabalho se você precisa para decodificar idnaou qualquer outra codificação
Alex
20
Isso é inútil. Você está codificando para UTF-8 e decodificando os bytes resultantes como UTF-8, terminando onde começou. Você está mantendo a CPU quente sem nenhum outro benefício.
Martijn Pieters
1
@MartijnPieters "terminando onde você começou" - não se você tiver sequências de escape em sua sequência, por exemplo: >>> '\ u0159'.encode (). Decode ()' ř '
Peter
1
@ Peter: não, você não precisa de codificação ou decodificação para isso. '\u0159'imprime exatamente a mesma saída. Você está confundindo a sintaxe literal da cadeia de caracteres com a representação canônica do valor.
Martijn Pieters
2
Você pode usar diretamente. Não há necessidade de codificar e decodificar novamente.
Aditya
10

Para Python3

html = """\\u003Cdiv id=\\u0022contenedor\\u0022\\u003E \\u003Ch2 class=\\u0022text-left m-b-2\\u0022\\u003EInformaci\\u00f3n del veh\\u00edculo de patente AA345AA\\u003C\\/h2\\u003E\\n\\n\\n\\n \\u003Cdiv class=\\u0022panel panel-default panel-disabled m-b-2\\u0022\\u003E\\n \\u003Cdiv class=\\u0022panel-body\\u0022\\u003E\\n \\u003Ch2 class=\\u0022table_title m-b-2\\u0022\\u003EInformaci\\u00f3n del Registro Automotor\\u003C\\/h2\\u003E\\n \\u003Cdiv class=\\u0022col-md-6\\u0022\\u003E\\n \\u003Clabel class=\\u0022control-label\\u0022\\u003ERegistro Seccional\\u003C\\/label\\u003E\\n \\u003Cp\\u003ESAN MIGUEL N\\u00b0 1\\u003C\\/p\\u003E\\n \\u003Clabel class=\\u0022control-label\\u0022\\u003EDirecci\\u00f3n\\u003C\\/label\\u003E\\n \\u003Cp\\u003EMAESTRO ANGEL D\\u0027ELIA 766\\u003C\\/p\\u003E\\n \\u003Clabel class=\\u0022control-label\\u0022\\u003EPiso\\u003C\\/label\\u003E\\n \\u003Cp\\u003EPB\\u003C\\/p\\u003E\\n \\u003Clabel class=\\u0022control-label\\u0022\\u003EDepartamento\\u003C\\/label\\u003E\\n \\u003Cp\\u003E-\\u003C\\/p\\u003E\\n \\u003Clabel class=\\u0022control-label\\u0022\\u003EC\\u00f3digo postal\\u003C\\/label\\u003E\\n \\u003Cp\\u003E1663\\u003C\\/p\\u003E\\n \\u003C\\/div\\u003E\\n \\u003Cdiv class=\\u0022col-md-6\\u0022\\u003E\\n \\u003Clabel class=\\u0022control-label\\u0022\\u003ELocalidad\\u003C\\/label\\u003E\\n \\u003Cp\\u003ESAN MIGUEL\\u003C\\/p\\u003E\\n \\u003Clabel class=\\u0022control-label\\u0022\\u003EProvincia\\u003C\\/label\\u003E\\n \\u003Cp\\u003EBUENOS AIRES\\u003C\\/p\\u003E\\n \\u003Clabel class=\\u0022control-label\\u0022\\u003ETel\\u00e9fono\\u003C\\/label\\u003E\\n \\u003Cp\\u003E(11)46646647\\u003C\\/p\\u003E\\n \\u003Clabel class=\\u0022control-label\\u0022\\u003EHorario\\u003C\\/label\\u003E\\n \\u003Cp\\u003E08:30 a 12:30\\u003C\\/p\\u003E\\n \\u003C\\/div\\u003E\\n \\u003C\\/div\\u003E\\n\\u003C\\/div\\u003E \\n\\n\\u003Cp class=\\u0022text-center m-t-3 m-b-1 hidden-print\\u0022\\u003E\\n \\u003Ca href=\\u0022javascript:window.print();\\u0022 class=\\u0022btn btn-default\\u0022\\u003EImprim\\u00ed la consulta\\u003C\\/a\\u003E \\u0026nbsp; \\u0026nbsp;\\n \\u003Ca href=\\u0022\\u0022 class=\\u0022btn use-ajax btn-primary\\u0022\\u003EHacer otra consulta\\u003C\\/a\\u003E\\n\\u003C\\/p\\u003E\\n\\u003C\\/div\\u003E"""
print(html.replace("\\/", "/").encode().decode('unicode_escape'))
krishna chandak
fonte
Eu te amo muito!
Gal Shahar
8

Não estou familiarizado com a biblioteca, mas se o seu problema é que você não deseja uma matriz de bytes, uma maneira fácil é especificar um tipo de codificação diretamente em uma conversão:

>>> my_byte_str
b'Hello World'

>>> str(my_byte_str, 'utf-8')
'Hello World'
Broper
fonte
Eles não têm um bytesobjeto para começar e str(bytes_object, codec)são apenas uma grafia alternativa bytes_object.decode(codec). Ambos falham se você realmente tiver um str.
Martijn Pieters
1
Você está certo, esta questão específica strjá tem uma . Essa resposta ainda pode ser útil para pessoas no futuro que possam ter matrizes de bytes (esse foi o problema que eu enfrentei quando me deparei com essa postagem originalmente).
Broper 27/02/19
Não tenho certeza de como você se deparou com este post, no entanto, porque my_byte_str.decodeexiste e funciona, e não lançará a exceção na pergunta.
Martijn Pieters
3

Ele já está decodificado no Python3. Tente diretamente, ele deve funcionar.

Aditya
fonte
1
Graças @Aditya A razão de eu chegar aqui é por causa da mudança de código com 2to3
Jesse Reza Khorasanee
0

Outras respostas sugerem isso, mas o problema pode surgir da expectativa de um objeto de bytes. No Python 3, a decodificação é válida quando você tem um objeto de bytes de classe. A execução da codificação antes da decodificação pode "consertar" o problema, mas é um par inútil de operações que sugere o problema nos upstream.

demongolem
fonte