El objeto 'str' no tiene el atributo 'decode'. ¿Error de Python 3?

182

Aquí está mi 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')

en este punto me sale el mensaje de error

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

Python 3 ya no tiene decodificación, ¿estoy en lo cierto? ¿Cómo puedo arreglar esto?

También en:

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

Estoy seleccionando solo el primer correo electrónico. ¿Cómo selecciono todo?

Martijn Pieters
fuente

Respuestas:

181

Está intentando decodificar un objeto que ya está decodificado . Tienes un str, ya no hay necesidad de decodificar desde UTF-8.

Simplemente suelte la .decode('utf-8')parte:

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

En cuanto a su fetch()llamada, está solicitando explícitamente solo el primer mensaje. Use un rango si desea recuperar más mensajes. Ver la documentación :

Las opciones de message_set para los comandos a continuación son una cadena que especifica uno o más mensajes para actuar. Puede ser un simple número de mensaje ( '1'), un rango de números de mensaje ( '2:4') o un grupo de rangos no contiguos separados por comas ( '1:3,6:9'). Un rango puede contener un asterisco para indicar un límite superior infinito ( '3:*').

Martijn Pieters
fuente
66
¿Hay una manera simple de hacer esto condicionalmente? (Solo quiero decodificar si el mensaje está codificado).
devinbost
55
@devinbost: en Python 3? Pruebe el tipo de objeto o el decodeatributo, o simplemente detecte la excepción. try: data = data.decode('...') except AttributeError: pass.
Martijn Pieters
2
@devinbost: sin embargo, generalmente es mejor decodificar más cerca de la fuente de sus datos, donde generalmente sabrá exactamente lo que tiene.
Martijn Pieters
37

Comience con Python 3, toda la cadena es un objeto unicode.

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

El código anterior es el mismo. Así que creo que deberías eliminar el .decode('utf-8'). Porque ya tienes el objeto unicode.

Neo Ko
fuente
37

Úselo por este método:

str.encode().decode()
Alireza
fuente
1
bytearray(str, 'encoding').decode('another_encoding')haría el trabajo si necesita decodificar idnao cualquier otra codificación
Alex
20
Esto es inútil Estás codificando a UTF-8, luego decodificando los bytes resultantes como UTF-8, terminando donde comenzaste. Mantiene la CPU caliente sin ningún otro beneficio.
Martijn Pieters
1
@MartijnPieters "terminando donde comenzaste" - no si tienes secuencias de escape en tu cadena, por ejemplo: >>> '\ u0159'.encode (). Decode ()' ř '
Peter
1
@ Peter: no, no necesitas codificación o decodificación para eso. '\u0159'imprime exactamente la misma salida. Está confundiendo la sintaxis literal de la cadena con la representación canónica del valor.
Martijn Pieters
2
Puede usar directamente, no hay necesidad de codificar y luego decodificar nuevamente.
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
fuente
¡Te quiero mucho!
Gal Shahar
8

No estoy familiarizado con la biblioteca, pero si su problema es que no desea una matriz de bytes, una forma fácil es especificar un tipo de codificación directamente en un molde:

>>> my_byte_str
b'Hello World'

>>> str(my_byte_str, 'utf-8')
'Hello World'
Broper
fuente
bytesPara empezar, no tienen un objeto, y str(bytes_object, codec)es solo una ortografía alternativa bytes_object.decode(codec). Ambos fallan si realmente tienes un strlugar.
Martijn Pieters
1
Tienes razón, esta pregunta específica ya tiene un str. Esta respuesta aún podría ser útil para las personas en el futuro que pueden tener matrices de bytes (este fue el problema que enfrenté cuando originalmente me topé con esta publicación).
Broper
Sin embargo, no estoy seguro de cómo tropezó con esta publicación, porque my_byte_str.decodeexiste y funciona, y no arrojará la excepción en la pregunta.
Martijn Pieters
3

Ya está decodificado en Python3, intente directamente, debería funcionar.

Aditya
fuente
1
Gracias @Aditya La razón por la que llegué aquí es por cambiar el código con 2to3
Jesse Reza Khorasanee
0

Otras respuestas lo insinúan, pero el problema puede surgir al esperar un objeto de bytes. En Python 3, la decodificación es válida cuando tiene un objeto de bytes de clase. Ejecutar la codificación antes de la decodificación puede "solucionar" el problema, pero es un par de operaciones inútiles que sugieren que el problema se encuentra en la fase inicial.

demongolem
fuente