案例研究:用Pandas和Outlook实现Excel文件的自动创建和分发

392 阅读5分钟

简介

我很高兴听到读者使用本博客中的概念来解决他们自己的问题。 当我看到只有几行python代码就能解决一个真正的商业问题并为组织节省大量时间和金钱的例子时,我总是感到惊讶。当人们在没有经过正式培训的情况下就能做到这一点时,我也会印象深刻--只需付出一些努力并愿意坚持学习就可以了。

这个例子来自于Mark Doll。我把它交给他来介绍他的背景。

我学习/使用Python大约3年了,以帮助实现业务流程和报告的自动化。我从来没有接受过任何关于Python的正式培训,但发现它是一个可靠的工具,对我的工作有帮助。

继续阅读,了解更多关于马克如何使用Python将收集和分类Excel文件并通过电子邮件发送给100多个用户的非常手动的过程自动化的细节。

问题所在

这里是Mark对问题的概述。

一个业务需求出现了,我们需要发送带有Excel附件的电子邮件给大约500个用户,这给我们带来了一个需要手工完成的大任务。使这项任务更加困难的是,我们必须从一个主Excel文件中按用户分割数据,以创建他们自己的特定文件,然后将该文件发往正确的用户。

想象一下,手动过滤、剪切和粘贴数据到一个文件中,然后保存并通过电子邮件发送,需要花费多少时间--500次!在这种情况下,我们就需要使用Python。使用这种Python方法,我们能够使整个过程自动化并节省宝贵的时间。

在我的经验中,我已经多次看到这种类型的问题。如果你没有编程语言的经验,那么它可能看起来很艰巨。有了Python,将这个乏味的过程自动化是非常可行的。下面是马克能够做的一个图形视图。

File paths

解决问题

第一步是让导入到位。

import datetime
import os
import shutil
from pathlib import Path
import pandas as pd
import win32com.client as win32

现在我们将用当前日期和我们的目录结构设置一些字符串。

## Set Date Formats
today_string = datetime.datetime.today().strftime('%m%d%Y_%I%p')
today_string2 = datetime.datetime.today().strftime('%b %d, %Y')

## Set Folder Targets for Attachments and Archiving
attachment_path = Path.cwd() / 'data' / 'attachments'
archive_dir = Path.cwd() / 'archive'
src_file = Path.cwd() / 'data' / 'Example4.xlsx'

让我们看一下我们需要处理的数据文件。

df = pd.read_excel(src_file)
df.head()

Excel file view

下一步是将所有的 CUSTOMER_ID交易组合在一起。 CUSTOMER_ID我们首先对 groupby

customer_group = df.groupby('CUSTOMER_ID')

在这种情况下,你可能不清楚什么是 customer_group。一个循环显示了我们如何处理这个分组的对象。

for ID, group_df in customer_group:
    print(ID)
A1000
A1001
A1002
A1005

这里是最后一个 group_df,显示了客户A1005的所有交易。

Excel file view

我们已经拥有了为每个客户创建一个Excel文件所需的一切,并存储在一个目录中供将来使用。

## Write each ID, Group to Individual Excel files and use ID to name each file with Today's Date
attachments = []
for ID, group_df in customer_group:
    attachment = attachment_path / f'{ID}_{today_string}.xlsx'
    group_df.to_excel(attachment, index=False)
    attachments.append((ID, str(attachment)))

attachments列表中包含客户ID和文件的完整路径。

[('A1000','c:\\Users\\chris\\notebooks\\2020-10\\data\\attachments\\A1000_01162021_12PM.xlsx'),('A1001','c:\\Users\\chris\\notebooks\\2020-10\\data\\attachments\\A1001_01162021_12PM.xlsx'),('A1002','c:\\Users\\chris\\notebooks\\2020-10\\data\\attachments\\A1002_01162021_12PM.xlsx'),('A1005','c:\\Users\\chris\\notebooks\\2020-10\\data\\attachments\\A1005_01162021_12PM.xlsx')]

为了使处理更容易,我们将该列表转换为一个数据框架。

df2 = pd.DataFrame(attachments, columns=['CUSTOMER_ID', 'FILE'])

File paths

最后的数据准备阶段是通过合并DataFrame来生成一个带有电子邮件地址的文件列表。

email_merge = pd.merge(df, df2, how='left')
combined = email_merge[['CUSTOMER_ID', 'EMAIL', 'FILE']].drop_duplicates()

这就得到了这个简单的DataFrame。

File paths

我们已经收集了客户的名单,他们的电子邮件和附件。现在我们需要用Outlook发送一封电子邮件。请参考这篇文章,了解这段代码的其他解释。

# Email Individual Reports to Respective Recipients
class EmailsSender:
    def __init__(self):
        self.outlook = win32.Dispatch('outlook.application')

    def send_email(self, to_email_address, attachment_path):
        mail = self.outlook.CreateItem(0)
        mail.To = to_email_address
        mail.Subject = today_string2 + ' Report'
        mail.Body = """Please find today's report attached."""
        mail.Attachments.Add(Source=attachment_path)
        # Use this to show the email
        #mail.Display(True)
        # Uncomment to send
        #mail.Send()

我们可以使用这个简单的类来生成电子邮件并附上Excel文件。

email_sender = EmailsSender()
for index, row in combined.iterrows():
    email_sender.send_email(row['EMAIL'], row['FILE'])

Outlook Email

最后一步是将文件移到我们的存档目录。

# Move the files to the archive location
for f in attachments:
    shutil.move(f[1], archive_dir)

总结

这个例子很好地将一个高度手工操作的过程自动化,在这个过程中可能有人做了大量的复制、粘贴和手工操作文件的工作。我希望马克开发的解决方案能够帮助你找出如何将你工作中一些比较痛苦的部分自动化。

我鼓励你用这个例子来确定你日常工作中的类似挑战。 也许你不需要处理100多个文件,但你可能有一个每周运行一次的手工流程。即使这个过程只需要1个小时,也可以把它作为一个跳板,找出如何使用Python来使它更容易。 学习Python的最好方法莫过于把它应用到你自己的一个问题中。

再次感谢马克抽出时间来指导我们学习这个内容的例子!