Опубликован: 22.12.2005 | Уровень: для всех | Доступ: платный
Лекция 7:

Работа с данными в различных форматах

Пакет email

Модули пакета email помогут разобрать, изменить и сгенерировать сообщение в формате RFC 2822. Наиболее часто RFC 2822 применяется в сообщениях электронной почты в Интернете.

В пакете есть несколько модулей, назначение которых (кратко) указано ниже:

Message

Модуль определяет класс Message - основной класс для представления сообщения в пакете email.

Parser

Модуль для разбора представленного в виде текста сообщения с получением объектной структуры сообщения.

Header

Модуль для работы с полями, в которых используется кодировка, отличная от ASCII.

Generator

Порождает текст сообщения RFC 2822 на основании объектной модели.

Utils

Различные утилиты, которые решают разнообразные небольшие задачи, связанные с сообщениями.

В пакете есть и другие модули, которые здесь рассматриваться не будут.

Разбор сообщения. Класс Message

Класс Message - центральный во всем пакете email. Он определяет методы для работы с сообщением, которое состоит из заголовка (header) и тела (payload). Поле заголовка имеет название и значение, разделенное двоеточием (двоеточие не входит ни в название, ни в значение). Названия полей нечувствительны к регистру букв при поиске значения, хотя хранятся с учетом регистра. В классе также определены методы для доступа к некоторым часто используемым сведениям (кодировке сообщения, типу содержимого и т.п.).

Следует заметить, что сообщение может иметь одну или несколько частей, в том числе вложенных друг в друга. Например, сообщение об ошибке доставки письма может содержать исходное письмо в качестве вложения.

Пример наиболее употребительных методов экземпляров класса Message с пояснениями:

>>> import email
>>> input_file = open("pr1.eml")
>>> msg = email.message_from_file(input_file)

Здесь используется функция email.message_from_file() для чтения сообщения из файла pr1.eml. Сообщение можно получить и из строки с помощью функции email.message_from_string(). А теперь следует произвести некоторые операции над этим сообщением (не стоит обращать внимания на странные имена - сообщение было взято из папки СПАМ). Доступ к полям по имени осуществляется так:

>>> print msg['from']
"felton olive" <zinakinch@thecanadianteacher.com>
>>> msg.get_all('received')
['from mail.onego.ru\n\tby localhost with POP3 (fetchmail-6.2.5 
polling mail.onego.ru account spam)\n\tfor spam@localhost 
(single-drop); Wed, 01 Sep 2004 15:46:33 +0400 (MSD)', 
'from thecanadianteacher.com ([222.65.104.100])\n\tby mail.onego.ru 
(8.12.11/8.12.11) with SMTP id i817UtUN026093;\n\tWed, 1 Sep 2004 
11:30:58 +0400']

Стоит заметить, что в электронном письме может быть несколько полей с именем received (в этом примере их два).

Некоторые важные данные можно получить в готовом виде, например, тип содержимого, кодировку:

>>> msg.get_content_type()
'text/plain'
>>> print msg.get_main_type(), msg.get_subtype()
text plain
>>> print msg.get_charset()
None
>>> print msg.get_params()
[('text/plain', ''), ('charset', 'us-ascii')]
>>> msg.is_multipart()
False

или список полей:

>>> print msg.keys()
['Received', 'Received', 'Message-ID', 'Date', 'From', 'User-Agent', 
'MIME-Version', 'To', 'Subject', 'Content-Type', 
'Content-Transfer-Encoding', 'Spam', 'X-Spam']

Так как сообщение состоит из одной части, можно получить его тело в виде строки:

>>> print msg.get_payload()
sorgeloosheid  hullw ifesh nozama decompresssequenceframes

Believe it or not, I have tried several sites to b"_"uy presription
medication. I should say that currently you are still be the best amony
...

Теперь будет рассмотрен другой пример, в котором сообщение состоит из нескольких частей. Это сообщение порождено вирусом. Оно состоит из двух частей: HTML-текста и вложенного файла с расширением cpl. Для доступа к частям сообщения используется метод walk(), который обходит все его части. Попутно следует собрать типы содержимого (в списке parts ), поля Content-Typect_fields ) и имена файлов (в filenames ):

import email
parts = []
ct_fields = []
filenames = []
f = open("virus.eml")
msg = email.message_from_file(f)
for submsg in msg.walk():
  parts.append(submsg.get_content_type())
  ct_fields.append(submsg.get('Content-Type', ''))
  filenames.append(submsg.get_filename())
  if submsg.get_filename():
      print "Длина файла:", len(submsg.get_payload())
f.close()
print parts
print ct_fields
print filenames

В результате получилось:

Длина файла: 31173
['multipart/mixed', 'text/html', 'application/octet-stream']
['multipart/mixed;\n        boundary="--------hidejpxkblmvuwfplzue"', 
'text/html; charset="us-ascii"', 
'application/octet-stream; name="price.cpl"']
[None, None, 'price.cpl']

Из списка parts можно увидеть, что само сообщение имеет тип multipart/mixed, тогда как две его части - text/html и application/octet-stream соответственно. Только с последней частью связано имя файла (price.cpl). Файл читается методом get_payload() и вычисляется его длина.

Кстати, в случае, когда сообщение является контейнером для других частей, get_payload() выдает список объектов-сообщений (то есть экземпляров класса Message ).

Сергей Крупко
Сергей Крупко

Добрый день.

Я сейчас прохожу курс  повышения квалификации  - "Профессиональное веб-программирование". Мне нужно получить диплом по этому курсу. Я так полагаю нужно его оплатить чтобы получить диплом о повышении квалификации. Как мне оплатить этот курс?

 

Павел Ялганов
Павел Ялганов

Скажите экзамен тоже будет ввиде теста? или там будет какое то практическое интересное задание?

Максим Чиндясов
Максим Чиндясов
Россия, Нижний Новгород
Ольга Коваль
Ольга Коваль
Беларусь, Минск