大家好!我是CSDN的Python新手博主~ 上一篇我们整合了Excel、Word、PDF、OCR的全能办公助手,很多小伙伴反馈“如果能定时自动运行就好了,比如每天早上8点自动处理Excel数据、生成报表并发送给领导,不用我手动点”。今天就带来超落地的新手实战项目——给办公助手添加定时任务功能!
本次将用Python内置的定时任务库,实现“按固定时间/固定间隔”自动执行办公任务,比如:每天9点自动读取Excel生成销售报表、每小时自动检查文件夹并处理新的PDF文件、每周一自动汇总上周数据发送邮件。全程代码复用之前的办公功能,注释详细,新手复制就能改造自己的工具,学会后彻底告别“重复手动操作”,自动化程度再上一个台阶~
一、本次学习目标
掌握2个核心定时库(schedule、time)的基础使用,实现“定时执行任务”;
学会“定时任务”与之前办公功能(Excel处理、邮件发送)的整合逻辑;
理解“后台运行定时任务”的实现方式,避免关闭窗口后任务停止;
掌握定时任务的“错误处理”和“日志记录”,确保任务稳定运行;
能根据实际需求,配置不同的定时规则(每日、每周、固定间隔)。
二、前期准备
- 安装定时任务库
安装定时任务库
pip install schedule -i https://pypi.tuna.tsinghua.edu.cn/simple
如需发送邮件,确保smtplib已安装(Python内置,无需额外装)
如需日志记录,确保logging模块可用(Python内置)
- 准备基础办公功能
注意:如果之前没实现邮件发送功能,文末会补充极简版邮件发送代码,直接复用即可!
三、实战:给办公助手加定时功能
- 核心定时需求拆解
定时规则:每天固定时间(9:00)执行;
执行流程:读取指定文件夹Excel→筛选销售数据(如销售额>2000)→生成部门销售额柱状图→保存Excel和图表→发送邮件(带附件);
辅助需求:记录任务运行日志(成功/失败时间、原因)、任务失败时给出提示。
- 完整代码(可直接复制运行)
-- coding: utf-8 --
import os
import time
import schedule
import logging
import matplotlib.pyplot as plt
from openpyxl import load_workbook, Workbook
import smtplib
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from email.mime.image import MIMEImage
from email.header import Header
====================== 全局配置 ======================
1. 基础路径配置(修改为你的实际路径)
EXCEL_FOLDER = r"C:\Users\张三\Desktop\每日销售数据" # Excel文件所在文件夹
SAVE_EXCEL_PATH = r"C:\Users\张三\Desktop\每日销售报表\当日销售筛选结果.xlsx" # 筛选后Excel保存路径
SAVE_CHART_PATH = r"C:\Users\张三\Desktop\每日销售报表\部门销售额柱状图.png" # 图表保存路径
LOG_FILE = r"C:\Users\张三\Desktop\每日销售报表\定时任务日志.txt" # 日志保存路径
2. 邮件配置(修改为你的邮箱信息)
SMTP_SERVER = “smtp.qq.com” # 邮箱SMTP服务器(QQ邮箱:smtp.qq.com;163邮箱:smtp.163.com)
SMTP_PORT = 465 # 端口(SSL加密,QQ/163均为465)
SENDER_EMAIL = “你的邮箱@qq.com” # 发件人邮箱
SENDER_PASSWORD = “你的邮箱授权码” # 邮箱授权码(不是登录密码,需在邮箱设置中开启SMTP获取)
RECEIVER_EMAIL = “领导邮箱@xxx.com” # 收件人邮箱
3. 其他配置
plt.rcParams[‘font.sans-serif’] = [‘SimHei’] # 解决matplotlib中文乱码
plt.rcParams[‘axes.unicode_minus’] = False
====================== 日志配置(新手必加,方便排查问题) ======================
def init_logger():
“”“初始化日志记录:记录任务运行状态(时间、成功/失败、原因)”“”
logging.basicConfig(
filename=LOG_FILE,
level=logging.INFO,
format=‘%(asctime)s - %(levelname)s - %(message)s’,
datefmt=‘%Y-%m-%d %H:%M:%S’
)
# 同时在控制台打印日志
console = logging.StreamHandler()
console.setLevel(logging.INFO)
formatter = logging.Formatter(‘%(asctime)s - %(levelname)s - %(message)s’)
console.setFormatter(formatter)
logging.getLogger().addHandler(console)
====================== 基础办公功能(复用之前的代码,稍作改造) ======================
def batch_read_excel(folder_path):
“”“批量读取Excel数据”“”
try:
excel_files = [f for f in os.listdir(folder_path) if f.lower().endswith(‘.xlsx’)]
if not excel_files:
logging.error(“目标文件夹内无xlsx格式文件!”)
return []
all_data = [] for excel_file in excel_files: file_path = os.path.join(folder_path, excel_file) wb = load_workbook(file_path) ws = wb[wb.sheetnames[0]] # 读取第一个sheet # 读取表头和数据 headers = [cell.value for cell in ws[1]] for row in ws.iter_rows(min_row=2, values_only=True): if row[0] is not None: # 跳过空行 all_data.append(dict(zip(headers, row))) logging.info(f"成功读取{len(excel_files)}个Excel文件,共{len(all_data)}条数据") return all_data except Exception as e: logging.error(f"读取Excel失败:{str(e)}") return []def filter_excel_data(data, filter_key=“销售额”, filter_condition=“>”, filter_value=2000):
“”“筛选数据(默认筛选销售额>2000的数据)”“”
try:
if not data:
logging.error(“无待筛选数据!”)
return []
filtered_data = [] for item in data: if filter_key not in item: logging.error(f"数据中无{filter_key}字段!") return [] item_value = item[filter_key] # 数值类型转换 try: item_value = float(item_value) filter_value = float(filter_value) except: logging.error(f"筛选字段{filter_key}不是数值类型!") return [] # 筛选逻辑 if filter_condition == ">" and item_value > filter_value: filtered_data.append(item) elif filter_condition == "<" and item_value < filter_value: filtered_data.append(item) else: logging.error(f"不支持的筛选条件:{filter_condition}") return [] # 保存筛选结果到Excel wb = Workbook() ws = wb.active ws.title = "当日销售筛选结果" headers = list(data[0].keys()) for col, header in enumerate(headers, 1): ws.cell(row=1, column=col, value=header) for row, item in enumerate(filtered_data, 2): for col, key in enumerate(headers, 1): ws.cell(row=row, column=col, value=item[key]) # 确保保存文件夹存在 os.makedirs(os.path.dirname(SAVE_EXCEL_PATH), exist_ok=True) wb.save(SAVE_EXCEL_PATH) logging.info(f"成功筛选出{len(filtered_data)}条数据,已保存至:{SAVE_EXCEL_PATH}") return filtered_data except Exception as e: logging.error(f"筛选Excel失败:{str(e)}") return []def generate_sales_chart(data):
“”“生成部门销售额柱状图”“”
try:
if not data:
logging.error(“无数据用于生成图表!”)
return False
# 按部门汇总销售额 dept_sales = {} for item in data: dept = item.get("部门", "未知部门") sales = float(item.get("销售额", 0)) dept_sales[dept] = dept_sales.get(dept, 0) + sales # 生成柱状图 plt.figure(figsize=(10, 6)) plt.bar(dept_sales.keys(), dept_sales.values(), color='#3498db') plt.title("当日各部门销售额汇总", fontsize=14) plt.xlabel("部门", fontsize=12) plt.ylabel("销售额(元)", fontsize=12) plt.xticks(rotation=45) plt.tight_layout() # 保存图表 os.makedirs(os.path.dirname(SAVE_CHART_PATH), exist_ok=True) plt.savefig(SAVE_CHART_PATH, dpi=300) plt.close() logging.info(f"成功生成销售额图表,已保存至:{SAVE_CHART_PATH}") return True except Exception as e: logging.error(f"生成图表失败:{str(e)}") return Falsedef send_email_with_attachment(subject=“当日销售报表”, content=“您好!附件为今日销售数据筛选结果及部门销售额图表,请查收。”):
“”“发送带附件的邮件”“”
try:
# 1. 构建邮件对象(带附件)
msg = MIMEMultipart()
msg[“From”] = Header(SENDER_EMAIL)
msg[“To”] = Header(RECEIVER_EMAIL)
msg[“Subject”] = Header(subject, “utf-8”)
# 2. 添加邮件正文 msg.attach(MIMEText(content, "plain", "utf-8")) # 3. 添加Excel附件 if os.path.exists(SAVE_EXCEL_PATH): with open(SAVE_EXCEL_PATH, 'rb') as f: excel_attachment = MIMEText(f.read(), 'base64', 'utf-8') excel_attachment["Content-Type"] = 'application/octet-stream' excel_attachment["Content-Disposition"] = f'attachment; filename="{os.path.basename(SAVE_EXCEL_PATH)}"' msg.attach(excel_attachment) logging.info("Excel附件添加成功") else: logging.warning("Excel附件文件不存在,跳过添加") # 4. 添加图表附件 if os.path.exists(SAVE_CHART_PATH): with open(SAVE_CHART_PATH, 'rb') as f: chart_attachment = MIMEText(f.read(), 'base64', 'utf-8') chart_attachment["Content-Type"] = 'application/octet-stream' chart_attachment["Content-Disposition"] = f'attachment; filename="{os.path.basename(SAVE_CHART_PATH)}"' msg.attach(chart_attachment) logging.info("图表附件添加成功") else: logging.warning("图表附件文件不存在,跳过添加") # 5. 连接SMTP服务器并发送邮件(SSL加密) with smtplib.SMTP_SSL(SMTP_SERVER, SMTP_PORT) as server: server.login(SENDER_EMAIL, SENDER_PASSWORD) server.sendmail(SENDER_EMAIL, RECEIVER_EMAIL, msg.as_string()) logging.info(f"邮件已成功发送至:{RECEIVER_EMAIL}") return True except Exception as e: logging.error(f"发送邮件失败:{str(e)}") return False====================== 核心定时任务函数 ======================
def daily_sales_task():
“”“每日销售报表定时任务:读取Excel→筛选→生成图表→发送邮件”“”
logging.info(“=”*50 + " 开始执行每日销售报表任务 " + “=”*50)
try:
# 1. 读取Excel数据
excel_data = batch_read_excel(EXCEL_FOLDER)
if not excel_data:
logging.error(“任务终止:未读取到有效Excel数据”)
return
# 2. 筛选数据(销售额>2000) filtered_data = filter_excel_data(excel_data) if not filtered_data: logging.error("任务终止:未筛选到有效数据") return # 3. 生成销售额图表 chart_success = generate_sales_chart(filtered_data) if not chart_success: logging.warning("图表生成失败,但继续执行邮件发送(仅含Excel附件)") # 4. 发送邮件 send_success = send_email_with_attachment() if send_success: logging.info("每日销售报表任务执行完成!") else: logging.error("任务执行完成,但邮件发送失败") except Exception as e: logging.error(f"每日销售报表任务执行失败:{str(e)}") finally: logging.info("="*50 + " 每日销售报表任务执行结束 " + "="*50 + "\n")====================== 定时任务配置与启动 ======================
def start_timed_task():
“”“配置定时规则并启动任务”“”
# 初始化日志
init_logger()
logging.info(“定时任务服务已启动,等待执行…”)
# 配置定时规则(重点!根据需求修改) # 规则1:每天早上9:00执行(常用) schedule.every().day.at("09:00").do(daily_sales_task) # 可选规则(新手可根据需求注释/启用) # 规则2:每小时执行一次 # schedule.every().hour.do(daily_sales_task) # 规则3:每隔30分钟执行一次 # schedule.every(30).minutes.do(daily_sales_task) # 规则4:每周一早上9:00执行 # schedule.every().monday.at("09:00").do(daily_sales_task) # 持续运行定时任务(循环检查) while True: schedule.run_pending() # 检查是否有任务需要执行 time.sleep(60) # 每隔60秒检查一次(避免占用过多资源)====================== 程序入口 ======================
ifname== “main”:
try:
start_timed_task()
except KeyboardInterrupt:
logging.info(“定时任务服务已手动终止”)
except Exception as e:
logging.error(f"定时任务服务异常终止:{str(e)}")
- 关键代码拆解(新手必看)
(1)定时任务核心库:schedule
1. 配置定时规则(每天9:00执行任务)
schedule.every().day.at(“09:00”).do(要执行的函数)
2. 循环检查任务(必须有,否则程序执行一次就结束)
while True:
schedule.run_pending() # 检查是否到任务执行时间
time.sleep(60) # 每60秒检查一次,节省资源
每小时执行:schedule.every().hour.do(task)
每隔30分钟执行:schedule.every(30).minutes.do(task)
每周一9:00执行:schedule.every().monday.at(“09:00”).do(task)
每天18:30执行:schedule.every().day.at(“18:30”).do(task)
(2)日志记录:新手排查问题的关键
记录内容:执行时间、成功/失败状态、错误原因;
保存位置:指定的日志文件(LOG_FILE),方便后续查看;
额外优化:同时在控制台打印日志,调试时更直观。
(3)办公功能与定时任务的整合逻辑
任务函数内按流程调用:读取Excel→筛选→生成图表→发送邮件;
每个步骤都加错误处理(try-except),避免一个步骤失败导致整个任务崩溃;
关键步骤(如保存文件、发送邮件)前,确保文件夹存在(用os.makedirs(exist_ok=True))。
(4)邮件发送功能补充
SMTP服务器和端口:QQ邮箱用smtp.qq.com:465,163邮箱用smtp.163.com:465;
授权码:不是邮箱登录密码,需在邮箱设置中开启“SMTP服务”,获取授权码(比如QQ邮箱在“设置→账户→开启POP3/SMTP服务”);
附件添加:用MIMEMultipart构建带附件的邮件,分别添加Excel和图表文件。
四、运行效果与测试方法
- 测试定时任务(新手必做)
临时测试规则:每隔1分钟执行一次
schedule.every(1).minutes.do(daily_sales_task)
能正常读取Excel数据并筛选;
图表能成功生成并保存;
邮件能正常发送,附件完整。
- 正式运行定时任务
Windows:打开cmd,切换到代码所在目录,执行python 定时办公助手.py,保持cmd窗口开启(关闭窗口任务会停止);
进阶:把程序打包成exe,设置为“Windows开机自启”,彻底不用手动启动(文末补充方法)。
五、新手避坑小贴士
定时任务不执行:检查定时规则是否正确(比如时间格式是否为“HH:MM”)、循环检查代码是否存在(while True + schedule.run_pending());
邮件发送失败:确认SMTP服务器、端口、授权码正确,收件人邮箱地址无误,且发件人邮箱已开启SMTP服务;
文件保存失败:检查保存路径是否正确(避免用中文特殊字符、空格),确保文件夹存在(用os.makedirs(exist_ok=True));
程序关闭后任务停止:Windows系统可把exe设置为开机自启(下文补充),或用“任务计划程序”创建定时任务,自动启动exe;
任务重复执行:确保循环检查的sleep时间合理(比如60秒),避免过短导致重复执行,过长导致任务延迟。
六、进阶扩展(新手可选)
- Windows开机自启设置:
把代码打包成exe(参考上一篇的PyInstaller打包方法);
按Win+R,输入shell:startup,打开开机启动文件夹;
创建exe文件的快捷方式,复制到开机启动文件夹,重启电脑后程序会自动运行。
多任务并行执行:如果需要同时执行多个定时任务(比如9:00执行销售报表,10:00执行库存统计),用threading模块实现多线程,避免任务阻塞;
任务失败重试:给关键任务添加重试机制,比如邮件发送失败后,间隔5分钟再试一次;
可视化定时任务管理:用tkinter给定时任务加GUI界面,支持“启动/暂停任务”“修改定时时间”“查看日志”;
异常报警:任务失败时,除了记录日志,还能发送短信报警(调用短信API,比如阿里云短信服务)。
七、总结与系列延伸
办公数据看板:用Flask/Django搭建简单的网页,实时展示定时任务处理的数据、图表;
云服务器部署:把定时任务部署到云服务器(比如阿里云、腾讯云),不用一直开自己的电脑;
AI辅助办公:结合ChatGPT API,实现“自动生成报表总结”“智能识别异常数据”等高级功能。
如果这篇文章对你有帮助,欢迎点赞收藏+关注!如果在配置定时任务、邮件发送时遇到问题,随时在评论区留言,我会逐一解答~ 新手不用怕复杂,先从简单的定时任务开始尝试,慢慢就能掌握自动化办公的核心技巧!