Как стать автором
Обновить

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

Время на прочтение6 мин
Количество просмотров4.7K
Центр непрерывного образования

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

Уже много лет я преподаю машинное обучение, программирование и анализ данных. Подготовка материалов лекций и общение со студентами доставляют огромное удовольствие, а вот рассылки, оформление ведомостей занимают большое количество времени и вызывают лишь скуку. Поэтому я решила автоматизировать эту часть работы с помощью 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)

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

Теги:
Хабы:
+6
Комментарии5

Публикации

Работа

Data Scientist
46 вакансий

Ближайшие события