Python办公自动化实战:批量处理Excel、PDF与自动发送邮件
一、自动化工作流架构与环境依赖
要实现从原始数据到最终送达的高效流转,关键在于厘清数据流与组件边界。典型的办公自动化流水线主要分为三层:数据采集与清洗层、文档合成与归档层、以及网络分发层。
在技术选型上,处理Excel推荐使用openpyxl(适合格式控制、公式与单元格级编辑)或pandas(适合大批量数据清洗统计);处理PDF文件通常采用pypdf(前身为PyPDF2,负责拆分、合并与元数据提取)与pdfplumber(负责高精度表格抽取);邮件发送则直接利用Python内置的标准库smtplib与email.mime,避免引入外部冗余依赖。
运行该自动化系统所需的基础环境依赖可以通过以下命令安装:
pip install openpyxl pandas pypdf pdfplumber
二、批量处理Excel:多表归集与数据清洗
在实际业务中,不同业务网点或团队往往会提交结构相同但名称各异的Excel表格。常见需求是将指定目录下的所有工作簿汇总为一张全量总表,并针对特定列执行合法性校验与格式清洗。
使用Python编写该过程时,建议借助pathlib.Path实现跨平台路径遍历,结合openpyxl或pandas的迭代器逐一处理。为避免不同表格表头存在空格或微小差异,需要在读取阶段统一进行列名修剪与类型转换。
以下代码演示了如何遍历输入目录,合并所有部门上报的销售表格,并按部门输出独立的汇总Excel文件:
from pathlib import Path
import pandas as pd
def process_and_split_excel(input_dir: str, output_dir: str):
input_path = Path(input_dir)
output_path = Path(output_dir)
output_path.mkdir(parents=True, exist_ok=True)
# 1. 过滤并扫描目标文件,排除Office开启时的临时文件
excel_files = [
f for f in input_path.glob("*.xlsx")
if not f.name.startswith("~$")
]
if not excel_files:
print("未检测到有效Excel文件,处理终止。")
return
all_data = []
# 2. 逐一读取与字段标准化
for file in excel_files:
df = pd.read_excel(file)
# 去除列名前后空格,统一格式
df.columns = df.columns.str.strip()
df["来源文件"] = file.name
all_data.append(df)
# 3. 合并全量数据并执行基础清洗
merged_df = pd.concat(all_data, ignore_index=True)
merged_df.dropna(subset=["员工编号", "业务日期"], inplace=True)
merged_df["金额"] = pd.to_numeric(merged_df["金额"], errors="coerce").fillna(0.0)
# 4. 按部门切分并输出独立工作簿供附件使用
for dept_name, group in merged_df.groupby("所属部门"):
target_file = output_path / f"业绩汇总_{dept_name}.xlsx"
with pd.ExcelWriter(target_file, engine="openpyxl") as writer:
group.to_excel(writer, sheet_name="明细数据", index=False)
print(f"已生成部门归档:{target_file.name}")
三、PDF自动化实战:单据拆分、合并与信息抽取
财务发票汇总单、员工合同或年度评价报告往往以PDF形式流转。通常需要从数百页的多合一PDF大文件中,根据目录或特定字段拆分成单一页面,或者将补充条款文件与主单据合并在一起。
使用pypdf操作PDF的核心在于PdfReader与PdfWriter对象的配合。需要特别注意的是,PDF文件中的页码索引始终从0开始;在提取文本用于判断归属人时,应注意不同版本PDF的编码兼容性。
下面是将多页PDF按页提取,并为每页附带通用的“公司须知说明页”的完整示例:
import re
from pathlib import Path
from pypdf import PdfReader, PdfWriter
def split_and_append_notice(source_pdf: str, notice_pdf: str, output_dir: str):
reader = PdfReader(source_pdf)
notice_reader = PdfReader(notice_pdf)
notice_page = notice_reader.pages[0] # 提取通用须知页
out_path = Path(output_dir)
out_path.mkdir(parents=True, exist_ok=True)
dept_pattern = re.compile(r"所属部门[::]\s*(\w+)")
for idx, page in enumerate(reader.pages):
text = page.extract_text() or ""
match = dept_pattern.search(text)
dept_name = match.group(1) if match else f"未识别_{idx+1}"
# 构造专属PDF文档
writer = PdfWriter()
writer.add_page(page) # 添加个人/部门专属页
writer.add_page(notice_page) # 附加通用须知页
dest_file = out_path / f"核对单_{dept_name}.pdf"
with open(dest_file, "wb") as f:
writer.write(f)
print(f"已拆分并生成PDF单据:{dest_file.name}")
四、邮件自动化与附件批量分发实战
数据报表与PDF单据生成完毕后,最后一个关键步骤是通过电子邮件将对应附件定向推送至责任人。处理邮件时必须保证:
- 附件名称编码:必须使用
email.header.Header进行UTF-8编码,否则Outlook或Foxmail等客户端易将中文文件名显示为乱码或ATT00001.bin。 - 认证凭据隔离:严禁将邮箱账号密码硬编码在代码中,应通过环境变量或受限配置文件读取授权码。
- 频控与重试:主流企业邮箱对单位时间内的发送频率有严格限制(如每分钟不超过30封),批量发送循环内必须引入延时并捕获异常。
邮件组装与安全分发的核心实现代码如下:
import os
import time
import smtplib
from pathlib import Path
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.mime.application import MIMEApplication
from email.header import Header
def send_automated_email(
smtp_server: str,
smtp_port: int,
sender_email: str,
auth_code: str,
recipient_email: str,
recipient_name: str,
attachment_paths: list[str]
):
# 1. 创建多部件邮件对象
msg = MIMEMultipart()
msg["From"] = f"{Header('自动化管理系统', 'utf-8')} <{sender_email}>"
msg["To"] = recipient_email
msg["Subject"] = Header(f"【工作通知】{recipient_name} 本月报表与单据已归档", "utf-8")
# 2. 编写HTML个性化正文
html_content = f"""
<div style="font-family: Arial, sans-serif; color: #333;">
<p>尊敬的 <b>{recipient_name}</b>:</p>
<p>附件为您本周期的业务统计Excel及PDF归档单据,系统已自动生成并核验完毕。</p>
<p style="color: #666; font-size: 13px;">本邮件由办公自动化脚本统一分发,请查收后核对无误并存档。</p>
</div>
"""
msg.attach(MIMEText(html_content, "html", "utf-8"))
# 3. 遍历挂载附件并处理中文文件名编码
for file_path in attachment_paths:
path = Path(file_path)
if not path.is_file():
continue
with open(path, "rb") as f:
part = MIMEApplication(f.read(), Name=path.name)
# 正确设置Content-Disposition以避免客户端乱码
part.add_header(
"Content-Disposition",
"attachment",
filename=("utf-8", "", path.name)
)
msg.attach(part)
# 4. 建立SSL安全连接并发送
with smtplib.SMTP_SSL(smtp_server, smtp_port) as server:
server.login(sender_email, auth_code)
server.sendmail(sender_email, [recipient_email], msg.as_string())
print(f"邮件已成功投递至:{recipient_email}")
五、端到端全流程集成与异常防御总结
在将各个环节串联为生产环境脚本时,务必建立完善的异常防御体系。单次批量任务中,任何一个表格解析失败或某一封邮件投递超时都不应阻断整个批处理流程。
本站声明
本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。













