Python для преподавателя: как я использую код, чтобы автоматизировать работу

от автора

Центр непрерывного образования

факультет компьютерных наук НИУ ВШЭ

Уже много лет я преподаю машинное обучение, программирование и анализ данных. Подготовка материалов лекций и общение со студентами доставляют огромное удовольствие, а вот рассылки, оформление ведомостей занимают большое количество времени и вызывают лишь скуку. Поэтому я решила автоматизировать эту часть работы с помощью Python. Также наши сотрудники из учебного офиса тратят значительное количество времени, вручную создавая документы и рассылки. Приведенные ниже скрипты могут быть полезны не только в преподавательской, но и в разнообразной менеджерской работе.

По сути, передо мной и коллегами обычно стоят две типовыезадачи, которые я бы и хотела автоматизировать:

  • персонализированные рассылки

  • генерация документов (служебные записки, заявления)

И в рассылках, как и при генерации документов, хотелось бы автоматически подтягивать данные из большого количества excel‑таблиц, в которые собираются данные о студентах от преподавателей, ассистентов и учебного офиса.

Маргарита Бурова

Преподаватель и эксперт Центра непрерывного образования ФКН НИУ ВШЭ, руководитель Edtech-программ по DS и DA Wildberries&Russ

Автоматизированные рассылки

Здесь основной фокус стоит на том, чтобы большое количество людей получили персонализированные рассылки (в которых, к примеру, будет содержаться уникальный код доступа или еще какая‑то личная информация)

Для начала необходимо подключиться к почтовому серверу под логином и паролем отправителя. Для этого я использую следующий код:

HOST = "smtp.hse.ru" PASSWORD = "ВашПароль"  # тут записывается пароль к почте PORT = 587 SENDER_EMAIL = # тут записывается адрес отправителя smtpserver = smtplib.SMTP(HOST, PORT) smtpserver.starttls() smtpserver.login("логин отправителя", PASSWORD)

Поясню основные моменты:

HOST = "smtp.hse.ru"

Сначала мы задаем адрес SMTP‑сервера нашего вуза, Высшей школы экономики (hse.ru). Этот сервер будет использоваться для отправки электронной почты.

PORT = 587

Для порта устанавливается значение 587. Это стандартный порт для SMTP‑сервера с использованием TLS (Transport Layer Security). Он обеспечивает безопасную передачу данных.

Далее следует установка соединения с SMTP‑сервером:

smtpserver = smtplib.SMTP(HOST, PORT)

Мы создаем объект, который устанавливает соединение с указанным SMTP‑сервером по заданному хосту и порту.

И после этого инициализируется безопасное соединение:

smtpserver.starttls()

Осталось только авторизоваться:

smtpserver.login("логин", PASSWORD)

Таким образом, мы выполнили подготовительную часть, и если авторизация прошла успешно — можно переходить к рассылке. Рассылку сразу будем делать по списку почт.

Допустим, у меня есть три почтовых адреса:

mails = [‘почта1@gmail.com’, ‘почта2@yandex.ru’, ‘почта3@gmail.com‘]

В реальности, конечно, их может быть сто или больше — и я подгружаю их из таблички.

Составляем непосредственно тело письма:

for mail in mails:     msg = MIMEMultipart()                                  # Создаем сообщение     msg["From"] = SENDER_EMAIL                             # Добавляем адрес отправителя     msg['To'] = mail                                       # Добавляем адрес получателя     msg["Subject"] = Header('Орг.инфо про курс', 'utf-8')  # Пишем тему сообщения     text = ‘текст’     msg.attach(MIMEText(text, 'html', 'utf-8'))  # Добавляем форматированный текст сообщения     smtpserver.send_message(msg) # отправляем сообщение 

В начале создается новый объект MIMEMultipart, который представляет собой многочастное сообщение электронной почты. Это позволит нам добавить различные части к нашему сообщению, такие как текст, изображения и вложения. Или вообще отформатировать сообщение с помощью HTML‑разметки.

Далее добавляем основные характеристики письма: адрес отправителя (у меня он заранее определен в переменную), адрес получателя (будет каждый раз разный, мы в цикле как раз перебираем адреса) и тему сообщения.

В переменную text я записала здесь просто строку, но в реальности письма, как правило, носят персонализированный характер, поэтому сюда может добавиться информация для конкретного человека.

После добавления текста письма — оно отправляется! Таким образом, я за один раз делаю рассылку по всем студентам.

Для того, чтобы добавлять персонализированную информацию, я подтягиваю данные из таблицы.

К примеру, у меня есть табличка с данными о студентах:

пример таблицы с данными о студентах

пример таблицы с данными о студентах

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

Можно использовать для этого pandas:

for i in range(df.shape[0]):     msg = MIMEMultipart()                                            msg['To'] = df['E-mail'].iloc[i] # добавляю адрес из i-ой строки     msg["Subject"] = Header('Орг.инфо про курс', 'utf-8')               text = f'Добрый день, {df["Имя"].iloc[i]}' # добавляю имя из i-ой строки     msg.attach(MIMEText(text, 'html', 'utf-8'))  сообщения     smtpserver.send_message(msg)

В приведенном выше коде из персонализации я просто добавляю обращение по имени, но, разумеется, можно добавлять и какую‑то еще информацию, записанную в таблицу.

Рассылка сделана, время сэкономлено!

Заполнение документов по шаблонам

Кроме рассылки писем есть вторая задача — генерация документов по шаблонам.

Достаточно часто нужно сгенерировать какие‑либо документы или заявления по шаблону. Причемданные, как правило, подтягиваются из экселевских таблиц.

Этот код у нас используют и сотрудники учебных офисов, поэтому он максимально приближен к обычной работе с таблицами и документами.

По сути, задача такая:

  • Снова есть уже знакомая нам таблица с информацией о студентах:

таблица с данными о студентах

таблица с данными о студентах
  • И заявление, в которое необходимо подставить эти данные:

пример заявления

пример заявления

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

Для решения задачи будем использовать два модуля: openpyxl и DocxTemplate.

Модуль openpyxl полезен для работы с файлами Microsoft Excel формата.xlsx и.xlsm непосредственно из Python. С его помощью вы можете программно создавать, читать, изменять и сохранять Excel‑файлы без необходимости использования самого приложения Excel. Его преимущество заключается в том, что им легко пользоваться людям, не очень глубоко знакомым с python, но при этом уверенно работающим в Excel. По сути, этот модуль позволяет работать с экселевскими файлами почти так же, как и в самом эксель. Именно поэтому я хотела бы показать его, а не pandas (в том числе, чтобы добавить разнообразия между двумя примерами)

Первоначально импортируем модуль openpyxl и открываем таблицу с данными, выбираем оттуда нужный лист:

import openpyxl wb = openpyxl.load_workbook(filename='table_final.xlsx') sheet = wb['Лист1']

Далее импортируем класс DocxTemplate и загружаем ранее созданный шаблон.

from docxtpl import DocxTemplate doc = DocxTemplate("temp_final.docx")

DocxTemplate нужен, чтобы автоматически создавать документы Word на основе шаблонов с пустыми полями. Он позволяет вставлять в эти шаблоны переменные из кода Python, что упрощает создание персонализированных документов, например, отчетов или счетов. По сути, нужно сделать «рыбу» документа, обозначив места для подстановки данных. И далее уже такой шаблон можно преобразовывать в экземпляр класса DocxTemplate и работать с ним.

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

for num in range(2,7):          name = sheet['A'+str(num)].value     course = sheet['B'+str(num)].value     group = sheet['C'+str(num)].value     op = sheet['D'+str(num)].value     mobile = sheet['E'+str(num)].value     mail = sheet['F'+str(num)].value     date = sheet['G'+str(num)].value.date()     context = {     'name': name,     'course': course,     'group': group,     'op': op,     'mobile': mobile,     'mail': mail,     'date' : date,     'now_date': today     }     doc.render(context)     doc.save(name+' заявление.docx')

Давайте разберем основные моменты:

 name = sheet['A'+str(num)].value

В данном кусочке кода из объекта sheet (представляющего рабочий лист электронных таблиц) считывается значение из ячейки в столбце ‘A’ и строке num. Часть ‘A’+str(num). Далее аналогичным образом из столбцов B, C, D, E и F текущей строки (num) считываются значения и присваиваются соответствующим переменным::

  • course — курс

  • group — группа

  • op — образовательная программа

  • mobile — номер мобильного телефона

  • mail — адрес электронной почты

date = sheet['G'+str(num)].value.date()

Здесь из столбца G текущей строки читается значение, которое предполагается датой. Метод.date() используется, чтобы получить только дату без времени.

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

today = str(date.today())

Это нужно для подписания документа сегодняшней датой.

В конце мы обрабатываем шаблон, заменяя в нем плейсхолдеры соответствующими значениями из словаря context. т. е., если в шаблоне есть плейсхолдер {{ name }}, он будет заменен на значение переменной name. И так происходит со всеми плейсхолдерами.

   doc.render(context)

После этого лишь сохраняем документ, и все! Таким образом можно сгенерировать огромное количество документов за раз. Что упрощает и автоматизирует работу.


ссылка на оригинал статьи https://habr.com/ru/articles/900728/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *