Разбирайте многоэлементную электронную почту с помощью частей с помощью Python

Я использую эту функцию для анализа электронной почты. Я могу разобрать «простые» многостраничные электронные письма, но при этом возникает ошибка (UnboundLocalError: локальная переменная «html», на которую ссылаются до назначения), когда электронное письмо определяет несколько границ (подчастей). Я хотел бы, чтобы сценарий разделял текст и части html и возвращал только часть html (если только нет html-части, верните текст).

def get_text(msg): text = "" if msg.is_multipart(): for part in msg.get_payload(): if part.get_content_charset() is None: charset = chardet.detect(str(part))['encoding'] else: charset = part.get_content_charset() if part.get_content_type() == 'text/plain': text = unicode(part.get_payload(decode=True),str(charset),"ignore").encode('utf8','replace') if part.get_content_type() == 'text/html': html = unicode(part.get_payload(decode=True),str(charset),"ignore").encode('utf8','replace') if html is None: return text.strip() else: return html.strip() else: text = unicode(msg.get_payload(decode=True),msg.get_content_charset(),'ignore').encode('utf8','replace') return text.strip() 

Как и комментарий, вы всегда проверяете html, но только объявляете его в одном из конкретных случаев. То что сообщение говорит вам, вы ссылаетесь html перед назначать его. В python неверно проверять, является ли что-то None, если оно не было назначено никому. Например, откройте интерактивную подсказку python:

 >>> if y is None: ... print 'none' ... Traceback (most recent call last): File "<stdin>", line 1, in <module> NameError: name 'y' is not defined 

Как вы можете видеть, вы не можете просто проверить, нет ли какой-либо переменной. Вернемся к вашему конкретному делу.

Сначала вам нужно установить html в None, а затем вы будете проверять, не осталось ли еще. т.е. отредактируйте свой код следующим образом:

 def get_text(msg): text = "" if msg.is_multipart(): html = None for part in msg.get_payload(): if part.get_content_charset() is None: charset = chardet.detect(str(part))['encoding'] else: charset = part.get_content_charset() if part.get_content_type() == 'text/plain': text = unicode(part.get_payload(decode=True),str(charset),"ignore").encode('utf8','replace') if part.get_content_type() == 'text/html': html = unicode(part.get_payload(decode=True),str(charset),"ignore").encode('utf8','replace') if html is None: return text.strip() else: return html.strip() else: text = unicode(msg.get_payload(decode=True),msg.get_content_charset(),'ignore').encode('utf8','replace') return text.strip() 

Это объясняет немного больше: http://code.activestate.com/recipes/59892-testing-if-a-variable-is-defined/

Вот тот же код с полезным предложением OlliM. Без этого изменения вы не сможете правильно разобрать контейнеры «multipart / alternative» в электронных письмах.

 import chardet def get_text(msg): """ Parses email message text, given message object This doesn't support infinite recursive parts, but mail is usually not so naughty. """ text = "" if msg.is_multipart(): html = None for part in msg.get_payload(): if part.get_content_charset() is None: charset = chardet.detect(str(part))['encoding'] else: charset = part.get_content_charset() if part.get_content_type() == 'text/plain': text = unicode(part.get_payload(decode=True),str(charset),"ignore").encode('utf8','replace') if part.get_content_type() == 'text/html': html = unicode(part.get_payload(decode=True),str(charset),"ignore").encode('utf8','replace') if part.get_content_type() == 'multipart/alternative': for subpart in part.get_payload(): if subpart.get_content_charset() is None: charset = chardet.detect(str(subpart))['encoding'] else: charset = subpart.get_content_charset() if subpart.get_content_type() == 'text/plain': text = unicode(subpart.get_payload(decode=True),str(charset),"ignore").encode('utf8','replace') if subpart.get_content_type() == 'text/html': html = unicode(subpart.get_payload(decode=True),str(charset),"ignore").encode('utf8','replace') if html is None: return text.strip() else: return html.strip() else: text = unicode(msg.get_payload(decode=True),msg.get_content_charset(),'ignore').encode('utf8','replace') return text.strip() 

Написание более элегантной структуры, которая не повторяет никакого кода, остается как упражнение для читателя.

Кроме того, ознакомьтесь с этой полезной схемой структуры контейнера .