第 97 课 - 项目实战:自动化办公脚本(文件处理、邮件、报告)
所属模块:模块十八:综合项目实战 难度:中级 标签:项目, 自动化, 脚本 上一课:项目实战:完成一个端到端的数据分析项目 下一课:项目实战:开发一个桌面 GUI 应用程序
学习目标
完成本课学习后,你将能够:
- 整合 Python 的文件处理、数据处理、报告生成和邮件发送能力,构建一个完整的自动化工作流。
- 使用
os和shutil模块进行文件与目录的自动化操作(如移动、重命名、清理)。 - 使用
csv或openpyxl等库读取数据文件并进行简单的汇总计算。 - 使用
xlsxwriter或openpyxl库创建结构清晰的 Excel 报告。 - 使用
smtplib和email库编写脚本,自动发送带有附件的电子邮件。
核心概念
自动化办公脚本的核心思想是将重复性、规则性强的手工操作,交给程序自动执行。在本课中,我们将围绕一个模拟的"周报自动化"场景,将以下三个关键环节串联起来:
- 文件处理 (File Handling):脚本的起点。我们需要从指定的文件夹(如
data/raw)中读取原始数据文件(如.csv销售记录),并在处理完毕后,将文件移动到存档目录(如data/archive),同时清理临时文件。 - 数据处理与报告生成 (Data Processing & Reporting):脚本的核心。读取原始数据后,使用 Python 进行计算(如本周销售总额、各产品销量排名),然后将结果和原始数据,以美观的格式(如带图表、表头)写入一个新的 Excel 工作簿(
report.xlsx)作为报告。 - 邮件发送 (Email Sending):脚本的终点。将生成的报告作为附件,通过 SMTP 协议自动发送给指定的收件人(如你的经理或团队),并附上一封简明的邮件正文。
这三步环环相扣,形成一个无人值守的自动化流水线。
代码示例
下面是一个整合了上述所有概念的脚本示例。它假设你在 sales_data.csv 文件中有如下的销售记录。
第一步:准备模拟数据文件 (sales_data.csv)
Date,Product,Quantity,UnitPrice
2023-10-01,Laptop,5,999.9
2023-10-01,Mouse,10,25.5
2023-10-02,Laptop,3,999.9
2023-10-02,Keyboard,8,75.0
2023-10-03,Mouse,12,25.5
第二步:自动化脚本 (auto_weekly_report.py)
import os
import shutil
import csv
import datetime
import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.base import MIMEBase
from email.mime.text import MIMEText
from email import encoders
import xlsxwriter # 需要安装: pip install xlsxwriter
# ==================== 1. 配置部分 ====================
RAW_DATA_DIR = 'data/raw' # 原始数据存放目录
ARCHIVE_DIR = 'data/archive' # 处理后的文件归档目录
REPORT_FILENAME = 'weekly_report.xlsx' # 生成的报告文件名
# 邮件配置(请替换为你的真实信息)
SMTP_SERVER = 'smtp.example.com'
SMTP_PORT = 587
SENDER_EMAIL = '[email protected]'
SENDER_PASSWORD = 'your_password' # 注意:此处为示例,实际应使用应用专用密码或环境变量
RECEIVER_EMAIL = ['[email protected]'] # 收件人列表
SUBJECT = f'自动化周报 - {datetime.date.today().strftime("%Y-%m-%d")}'
# ==================== 2. 核心功能函数 ====================
def process_sales_data(filepath):
"""读取并汇总CSV销售数据"""
total_revenue = 0
product_summary = {}
try:
with open(filepath, 'r', newline='', encoding='utf-8') as f:
reader = csv.DictReader(f)
for row in reader:
quantity = int(row['Quantity'])
unit_price = float(row['UnitPrice'])
revenue = quantity * unit_price
total_revenue += revenue
product = row['Product']
if product in product_summary:
product_summary[product] += quantity
else:
product_summary[product] = quantity
return total_revenue, product_summary
except FileNotFoundError:
print(f"错误:找不到数据文件 {filepath}")
return None, None
def create_excel_report(total_revenue, product_summary, output_path):
"""创建带图表的Excel报告"""
workbook = xlsxwriter.Workbook(output_path)
worksheet = workbook.add_worksheet('销售汇总')
# 添加格式
bold = workbook.add_format({'bold': True})
money_format = workbook.add_format({'num_format': '$#,##0.00'})
# 写入标题
worksheet.write('A1', '本周销售数据汇总', bold)
worksheet.write('A3', '总销售额:', bold)
worksheet.write('B3', total_revenue, money_format)
# 写入产品明细表
worksheet.write('A5', '产品', bold)
worksheet.write('B5', '总销量', bold)
row = 5
for product, qty in product_summary.items():
worksheet.write(row, 0, product)
worksheet.write(row, 1, qty)
row += 1
# 创建一个柱状图
chart = workbook.add_chart({'type': 'column'})
chart.add_series({
'name': '销量',
'categories': f'=销售汇总!$A$6:$A${row-1}', # 动态范围
'values': f'=销售汇总!$B$6:$B${row-1}',
})
chart.set_title({'name': '产品销量对比'})
chart.set_y_axis({'name': '销量(件)'})
worksheet.insert_chart('D2', chart)
workbook.close()
print(f"报告已生成: {output_path}")
def send_email_with_attachment(subject, body, attachment_path):
"""发送带附件的电子邮件"""
# 创建邮件对象
msg = MIMEMultipart()
msg['From'] = SENDER_EMAIL
msg['To'] = ', '.join(RECEIVER_EMAIL)
msg['Subject'] = subject
# 添加邮件正文
msg.attach(MIMEText(body, 'plain'))
# 添加附件
with open(attachment_path, 'rb') as attachment:
part = MIMEBase('application', 'octet-stream')
part.set_payload(attachment.read())
encoders.encode_base64(part)
part.add_header('Content-Disposition', f'attachment; filename={os.path.basename(attachment_path)}')
msg.attach(part)
# 发送邮件
try:
with smtplib.SMTP(SMTP_SERVER, SMTP_PORT) as server:
server.starttls() # 启用TLS加密
server.login(SENDER_EMAIL, SENDER_PASSWORD)
server.sendmail(SENDER_EMAIL, RECEIVER_EMAIL, msg.as_string())
print("邮件发送成功!")
except Exception as e:
print(f"邮件发送失败: {e}")
def archive_file(src_path, dest_dir):
"""将处理完的文件移动到归档目录"""
if not os.path.exists(dest_dir):
os.makedirs(dest_dir)
filename = os.path.basename(src_path)
dest_path = os.path.join(dest_dir, filename)
shutil.move(src_path, dest_path)
print(f"文件已归档至: {dest_path}")
# ==================== 3. 主程序:串联整个自动化流程 ====================
if __name__ == "__main__":
# 假设我们处理最新的数据文件(这里简化为固定文件名)
source_data_file = os.path.join(RAW_DATA_DIR, 'sales_data.csv')
# 步骤1: 数据处理
print("开始处理销售数据...")
total, summary = process_sales_data(source_data_file)
if total is not None:
# 步骤2: 生成报告
report_path = os.path.join(os.getcwd(), REPORT_FILENAME)
create_excel_report(total, summary, report_path)
# 步骤3: 发送邮件
email_body = "你好,\n\n请查收本周的销售数据汇总报告。\n\n此邮件由Python自动化脚本发送。"
send_email_with_attachment(SUBJECT, email_body, report_path)
# 步骤4: 归档原始数据文件
archive_file(source_data_file, ARCHIVE_DIR)
# 步骤5(可选):清理生成的报告(如果不需要在本地保留)
# os.remove(report_path)
print("自动化流程全部完成!")
else:
print("数据处理失败,流程终止。")
实践练习
练习 1(基础):文件批量重命名
编写一个函数 batch_rename(directory, old_ext, new_ext),它接受一个目录路径、旧文件扩展名和新文件扩展名作为参数。函数会将该目录下所有指定扩展名的文件,重命名为新的扩展名。
- 要求:使用
os模块。 - 示例:将目录
test_folder下所有.txt文件重命名为.md文件。 - 预期输出:在控制台打印每个重命名操作,如
Renamed: file1.txt -> file1.md。
练习 2(进阶):合并多个CSV文件
假设一个目录下有多个结构相同(列名一致)的 sales_data_week1.csv, sales_data_week2.csv 等文件。编写脚本,将它们合并成一个大的 all_sales_data.csv 文件。
- 要求:使用
csv模块读写文件。 - 提示:可以先读取第一个文件的表头,然后循环读取所有文件的数据行。
练习 3(综合挑战):自定义报表邮件 修改本课示例脚本,增加以下功能:
- 在邮件正文中,用文字简要列出"总销售额"和"销量最高的产品"。
- 在报告 Excel 中,除了柱状图,再增加一个显示销售额占比的饼图。
- (挑战) 脚本能自动检测
data/raw目录下最新的.csv文件,而不是写死文件名。
常见错误
- 文件路径错误:使用相对路径时,脚本的工作目录(
cwd)可能与你预期的不同。建议使用os.path.join和__file__变量来构建绝对路径。# 错误的写法(可能因运行脚本的位置不同而找不到文件) file_path = 'data/raw/sales.csv' # 更健壮的写法 script_dir = os.path.dirname(os.path.abspath(__file__)) file_path = os.path.join(script_dir, 'data', 'raw', 'sales.csv') - 邮件发送失败:
- 认证错误:很多邮箱(如QQ、163、Gmail)需要使用"应用专用密码"而非账户密码。请检查你的邮箱SMTP设置和密码。
- 连接错误:确保SMTP服务器地址和端口正确(例如Gmail用
smtp.gmail.com,端口587)。 - 防火墙/网络:确保你的网络环境允许连接外部的SMTP服务器。
- 编码问题:读取或写入包含中文等非ASCII字符的文件时,务必指定正确的编码(如
encoding='utf-8')。 - 资源未释放:使用
with open(...)语句可以确保文件被正确关闭,避免资源泄露。 - 第三方库未安装:示例中的
xlsxwriter需要提前安装。使用pip install xlsxwriter命令。
小结
本课通过一个"周报自动化"的完整项目,演示了如何将 Python 的文件操作、数据处理、报告生成和邮件发送能力融合,构建一个实用的办公自动化脚本。
关键要点回顾:
- 模块化设计:将复杂流程拆分为独立的函数(如
process_sales_data,create_excel_report),使代码更清晰、易维护、可复用。 - 文件处理三部曲:读取 -> 处理 -> 归档/清理,是自动化脚本的典型模式。
- 综合运用库:
csv处理表格数据,xlsxwriter/openpyxl生成专业报告,smtplib+email实现邮件功能。 - 健壮性考虑:在代码中加入
try...except块处理文件找不到、网络错误等异常,并妥善处理文件路径和编码问题。 - 安全提醒:切勿将密码等敏感信息硬编码在脚本中,应使用环境变量或配置文件来管理。
掌握了这个自动化流程框架后,你可以轻松地将其扩展到其他场景,如自动化数据备份、定期清理日志文件、监控系统状态并发送告警邮件等。