У объекта 'str' нет атрибута 'decode'. Ошибка Python 3?

182

Вот мой код:

import imaplib
from email.parser import HeaderParser

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

в этот момент я получаю сообщение об ошибке

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

У Python 3 больше нет декодирования, я прав? Как я могу это исправить?

Также в:

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

Я выбираю только 1-е письмо. Как выбрать все?

Мартейн Питерс
источник

Ответы:

181

Вы пытаетесь декодировать объект, который уже декодирован . У вас есть str, больше нет необходимости декодировать из UTF-8.

Просто оставьте .decode('utf-8')часть:

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

Что касается вашего fetch()звонка, вы явно просите только первое сообщение. Используйте диапазон, если вы хотите получить больше сообщений. Смотрите документацию :

Параметры message_set для команд ниже - это строка, определяющая одно или несколько сообщений, с которыми нужно действовать. Это может быть просто номер сообщения ( '1'), диапазон номеров сообщений ( '2:4') или группа несмежных диапазонов, разделенных запятыми ( '1:3,6:9'). Диапазон может содержать звездочку для обозначения бесконечной верхней границы ( '3:*').

Мартейн Питерс
источник
6
Есть ли простой способ сделать это условно? (Я хочу декодировать, только если сообщение закодировано.)
devinbost
5
@devinbost: в Python 3? Проверьте тип объекта или decodeатрибут, или просто перехватите исключение. try: data = data.decode('...') except AttributeError: pass,
Мартин Питерс
2
@devinbost: однако, вам, как правило, лучше декодировать ближе к источнику ваших данных, где вы будете точно знать, что у вас есть.
Мартин Питерс
37

Начните с Python 3, вся строка является объектом Unicode.

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

код перед тем же. Поэтому я думаю, что вы должны удалить .decode('utf-8'). Потому что вы уже получили объект Unicode.

Нео Ко
источник
37

Используйте это этим методом:

str.encode().decode()
Алиреза
источник
1
bytearray(str, 'encoding').decode('another_encoding')будет делать эту работу, если вам нужно декодировать idnaили любую другую кодировку
Алекс
20
Это бесполезно. Вы кодируете в UTF-8, затем декодируете полученные байты как UTF-8, заканчивая тем, с чего начали. Вы держите процессор в тепле без других преимуществ.
Мартин Питерс
1
@MartijnPieters «заканчивается там, где вы начали» - нет, если в вашей строке есть escape-последовательности, например: >>> '\ u0159'.encode (). Decode ()' ř '
Питер
1
@Peter: нет, вам не нужно кодирование или декодирование для этого. '\u0159'печатает точно такой же вывод. Вы путаете синтаксис строкового литерала с каноническим представлением значения.
Мартин Питерс
2
Вы можете напрямую использовать, нет необходимости кодировать, а затем декодировать снова.
Адитья
10

Для 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'))
Кришна Чандак
источник
Я так тебя люблю!
Гал Шахар
8

Я не знаком с библиотекой, но если ваша проблема в том, что вам не нужен байтовый массив, один простой способ - указать тип кодировки прямо в приведении:

>>> my_byte_str
b'Hello World'

>>> str(my_byte_str, 'utf-8')
'Hello World'
Broper
источник
У них нет bytesобъекта для начала, и str(bytes_object, codec)это просто альтернативное написание bytes_object.decode(codec). Оба не удастся, если у вас действительно есть strвместо.
Мартин Питерс
1
Вы правы, этот конкретный вопрос уже есть str. Этот ответ все еще может быть полезен людям в будущем, которые могут иметь байтовые массивы (с этой проблемой я столкнулся, когда впервые наткнулся на этот пост).
Брофер
Я не уверен, как вы наткнулись на этот пост, однако, потому что my_byte_str.decodeсуществует и работает, и не будет бросать исключение в вопросе.
Мартин Питерс
3

Он уже декодирован в Python3, попробуйте напрямую, он должен работать.

Адитья
источник
1
Спасибо @Aditya Причина, по которой я приехал сюда, из-за переключения кода с 2to3
Джесси Реза Хорасани
0

Другие ответы как бы намекают на это, но проблема может возникнуть из-за ожидания байтового объекта. В Python 3 декодирование допустимо, когда у вас есть объект байтов класса. Выполнение кодирования перед декодированием может «исправить» проблему, но это бесполезная пара операций, которые предлагают проблему, стоящую перед нами.

demongolem
источник