用 Python 打造你的个人自动化工作流:从文件整理到定时日报
本文覆盖 7 大高频场景、11 个可直接运行的代码片段,并提供一套完整的「每日自动日报」工作流。无需复杂架构,只需 Python 标准库 + 几个轻量第三方包,即可把重复劳动交给脚本。
一、为什么需要个人自动化?
作为开发者,我们每天都在经历这样的场景:
- 下载文件夹堆积如山,找文件像考古;
- 每周一要手动汇总 Excel 报表,复制粘贴到眼花;
- 想监控某个商品价格,却不得不每天打开网页查看;
- 定时发送日报/周报,内容固定但操作重复。
这些任务并不复杂,却极度消耗注意力。自动化的核心目的不是「偷懒」,而是把认知资源留给真正需要创造性思考的工作。
Python 凭借其丰富的生态和简洁的语法,是个人自动化领域性价比最高的工具。本文将从「文件系统 → 办公文档 → 网络请求 → 系统调度」四个层级,逐步搭建你的自动化能力。
二、环境准备:核心依赖一览
在开始之前,建议创建一个独立的虚拟环境:
python -m venv automation-env
source automation-env/bin/activate # Windows: automation-env\Scripts\activate
pip install openpyxl python-docx requests beautifulsoup4 \
selenium schedule pyautogui Pillow PyPDF2 \
lxml pandas
💡 提示:如果你只关注某几个场景,可以按需安装,不必一次性全部引入。
三、文件系统自动化:从「混乱」到「秩序」
3.1 智能分类下载文件夹
下载文件夹是最常见的「数字垃圾场」。以下脚本按文件后缀自动归类,且具备幂等性——多次运行不会重复移动已整理的文件。
from pathlib import Path
import shutil
DOWNLOADS = Path.home() / "Downloads"
CATEGORIES = {
"Images": [".jpg", ".jpeg", ".png", ".gif", ".webp", ".bmp"],
"Documents": [".pdf", ".docx", ".txt", ".xlsx", ".pptx", ".md"],
"Archives": [".zip", ".rar", ".7z", ".tar.gz", ".tgz"],
"Videos": [".mp4", ".avi", ".mkv", ".mov", ".wmv"],
"Music": [".mp3", ".wav", ".flac", ".aac"],
"Executables": [".exe", ".msi", ".dmg", ".pkg"],
}
def organize_downloads():
"""按文件类型自动分类下载文件夹内容"""
moved_count = 0
for file_path in DOWNLOADS.iterdir():
if not file_path.is_file():
continue
# 跳过已分类文件夹内的文件
if file_path.parent.name in CATEGORIES:
continue
for folder_name, extensions in CATEGORIES.items():
if file_path.suffix.lower() in extensions:
target_dir = DOWNLOADS / folder_name
target_dir.mkdir(exist_ok=True)
# 处理重名冲突
destination = target_dir / file_path.name
counter = 1
while destination.exists():
stem = file_path.stem
suffix = file_path.suffix
destination = target_dir / f"{stem}_{counter}{suffix}"
counter += 1
shutil.move(str(file_path), str(destination))
moved_count += 1
print(f"✅ 已移动: {file_path.name} -> {folder_name}/")
break
print(f"\n整理完成,共处理 {moved_count} 个文件。")
if __name__ == "__main__":
organize_downloads()
设计亮点:
- 使用
pathlib而非os.path,代码更具可读性; - 自动处理重名文件(追加
_1,_2后缀); - 跳过已分类目录,避免误操作。
3.2 批量重命名与格式转换
import os
from pathlib import Path
def batch_rename(directory: str, pattern: str, replacement: str, dry_run: bool = True):
"""
批量重命名文件
:param dry_run: 为 True 时只预览,不实际执行
"""
target_dir = Path(directory)
renamed = 0
for file_path in target_dir.iterdir():
if file_path.is_file() and pattern in file_path.name:
new_name = file_path.name.replace(pattern, replacement)
new_path = target_dir / new_name
if dry_run:
print(f"[预览] {file_path.name} -> {new_name}")
else:
file_path.rename(new_path)
renamed += 1
print(f"[已重命名] {file_path.name} -> {new_name}")
if not dry_run:
print(f"\n共重命名 {renamed} 个文件")
# 使用示例:先预览,确认无误后执行
# batch_rename("/path/to/files", "2025_", "2026_", dry_run=True)
# batch_rename("/path/to/files", "2025_", "2026_", dry_run=False)
⚠️ 避坑指南:批量重命名前务必开启
dry_run模式预览。一旦误操作,恢复成本极高。
四、办公文档自动化:解放复制粘贴
4.1 零代码模板生成 Excel 报表
openpyxl 是处理 .xlsx 文件的最佳选择。以下示例展示如何生成带样式、公式和自动列宽的报表。
import openpyxl
from openpyxl.styles import Font, PatternFill, Alignment, Border, Side
from openpyxl.utils import get_column_letter
def create_formatted_report(data: list[list], output_path: str, title: str = "月度报表"):
wb = openpyxl.Workbook()
ws = wb.active
ws.title = title
# 定义样式
header_font = Font(bold=True, color="FFFFFF", size=12)
header_fill = PatternFill(start_color="366092", end_color="366092", fill_type="solid")
header_align = Alignment(horizontal="center", vertical="center")
thin_border = Border(
left=Side(style='thin'),
right=Side(style='thin'),
top=Side(style='thin'),
bottom=Side(style='thin')
)
# 写入表头
headers = ["日期", "项目", "收入", "支出", "净利润", "备注"]
ws.append(headers)
# 表头样式
for col_num, header in enumerate(headers, 1):
cell = ws.cell(row=1, column=col_num)
cell.font = header_font
cell.fill = header_fill
cell.alignment = header_align
cell.border = thin_border
# 写入数据
for row_data in data:
ws.append(row_data)
# 添加公式行(净利润列自动计算)
last_row = len(data) + 1
for row in range(2, last_row + 1):
income_cell = ws.cell(row=row, column=3)
expense_cell = ws.cell(row=row, column=4)
profit_cell = ws.cell(row=row, column=5)
profit_cell.value = f"={income_cell.coordinate}-{expense_cell.coordinate}"
profit_cell.number_format = '#,##0.00'
# 自动调整列宽
for column in ws.columns:
max_length = 0
column_letter = get_column_letter(column[0].column)
for cell in column:
try:
if cell.value:
max_length = max(max_length, len(str(cell.value)))
except:
pass
adjusted_width = min(max_length + 2, 50)
ws.column_dimensions[column_letter].width = adjusted_width
# 冻结首行
ws.freeze_panes = "A2"
wb.save(output_path)
print(f"📊 报表已生成: {output_path}")
# 示例数据
sample_data = [
["2026-06-01", "项目A", 15000, 5000, "", "正常推进"],
["2026-06-02", "项目B", 28000, 12000, "", "客户追加需求"],
["2026-06-03", "内部工具", 0, 3000, "", "基础设施投入"],
]
# create_formatted_report(sample_data, "monthly_report.xlsx")
4.2 基于模板的 Word 文档生成
对于合同、邀请函等格式固定、内容变化的文档,使用模板替换是最优雅的方案。
from docx import Document
from docx.shared import Pt, RGBColor, Inches
from docx.enum.text import WD_ALIGN_PARAGRAPH
def generate_from_template(template_path: str, output_path: str, replacements: dict):
"""
基于模板生成 Word 文档
:param replacements: 占位符 -> 实际值的映射,如 {"{{COMPANY}}": "某某科技"}
"""
doc = Document(template_path)
# 替换段落中的占位符
for paragraph in doc.paragraphs:
for placeholder, value in replacements.items():
if placeholder in paragraph.text:
# 保留原有样式的情况下替换文本
paragraph.text = paragraph.text.replace(placeholder, value)
# 重新应用字体样式(因为 text 替换会重置 runs)
for run in paragraph.runs:
run.font.name = '微软雅黑'
run.font.size = Pt(10.5)
# 替换表格中的占位符
for table in doc.tables:
for row in table.rows:
for cell in row.cells:
for placeholder, value in replacements.items():
if placeholder in cell.text:
cell.text = cell.text.replace(placeholder, value)
doc.save(output_path)
print(f"📄 文档已生成: {output_path}")
# 使用示例
# replacements = {
# "{{COMPANY}}": "未来科技有限公司",
# "{{DATE}}": "2026年6月8日",
# "{{AMOUNT}}": "¥50,000.00",
# "{{SIGNATURE}}": "___________"
# }
# generate_from_template("contract_template.docx", "contract_20260608.docx", replacements)
📌 模板制作建议:在 Word 中预先设计好排版,用
{{VARIABLE}}作为占位符,直观且不易与正常文本混淆。
五、网络自动化:爬虫、监控与通知
5.1 轻量级网页数据抓取
不需要浏览器驱动的场景,用 requests + BeautifulSoup 效率更高。
import requests
from bs4 import BeautifulSoup
import time
class PriceMonitor:
def __init__(self, target_price: float, webhook_url: str = None):
self.target_price = target_price
self.webhook_url = webhook_url
self.headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"
}
self.session = requests.Session()
def check_price(self, url: str, selector: str) -> dict:
"""检查商品价格并返回状态"""
try:
response = self.session.get(url, headers=self.headers, timeout=10)
response.raise_for_status()
soup = BeautifulSoup(response.text, "lxml")
price_element = soup.select_one(selector)
if not price_element:
return {"status": "error", "message": "未找到价格元素"}
# 清洗价格文本
price_text = price_element.text.strip()
price = float(''.join(filter(lambda x: x.isdigit() or x == '.', price_text)))
result = {
"status": "success",
"current_price": price,
"target_met": price <= self.target_price,
"timestamp": time.strftime("%Y-%m-%d %H:%M:%S")
}
if result["target_met"]:
print(f"🚨 价格达标!当前: ¥{price}, 目标: ¥{self.target_price}")
# 可在此接入邮件/钉钉/企业微信通知
else:
print(f"ℹ️ 当前价格: ¥{price}, 继续监控...")
return result
except requests.RequestException as e:
return {"status": "error", "message": str(e)}
# 使用示例
# monitor = PriceMonitor(target_price=2999.0)
# result = monitor.check_price("https://example.com/product", ".price-current")
5.2 浏览器自动化:处理复杂交互
当网页需要登录、JavaScript 渲染或复杂交互时,Selenium 或 Playwright 是更好的选择。
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.chrome.service import Service
def auto_login_and_scrape(url: str, username: str, password: str, chrome_driver_path: str = None):
"""
自动登录并抓取需要认证后才能查看的数据
"""
options = Options()
# 生产环境建议开启无头模式
# options.add_argument("--headless")
options.add_argument("--disable-gpu")
options.add_argument("--window-size=1920,1080")
options.add_argument("--no-sandbox")
# 防止被检测为自动化工具
options.add_experimental_option("excludeSwitches", ["enable-automation"])
options.add_experimental_option('useAutomationExtension', False)
if chrome_driver_path:
service = Service(chrome_driver_path)
driver = webdriver.Chrome(service=service, options=options)
else:
driver = webdriver.Chrome(options=options)
try:
driver.get(url)
# 显式等待:等待元素可交互
wait = WebDriverWait(driver, 10)
username_input = wait.until(EC.presence_of_element_located((By.ID, "username")))
password_input = driver.find_element(By.ID, "password")
login_button = driver.find_element(By.ID, "login-btn")
username_input.send_keys(username)
password_input.send_keys(password)
login_button.click()
# 等待登录后的某个标志性元素出现
dashboard = wait.until(EC.presence_of_element_located((By.CLASS_NAME, "dashboard-data")))
# 抓取数据
data = {
"dashboard_text": dashboard.text,
"cookies": {c['name']: c['value'] for c in driver.get_cookies()}
}
print(f"✅ 登录成功,获取数据: {data['dashboard_text'][:100]}...")
return data
except Exception as e:
print(f"❌ 操作失败: {e}")
# 失败时截图留存
driver.save_screenshot("error_screenshot.png")
raise
finally:
driver.quit()
🔐 安全提醒:切勿在代码中硬编码密码。建议使用环境变量或密钥管理服务:
import os password = os.environ.get("PORTAL_PASSWORD")
六、系统级自动化:让脚本自己跑起来
6.1 定时任务调度(跨平台)
schedule 库非常适合个人本地的定时任务,语法直观,无需学习 Crontab 语法。
import schedule
import time
import signal
import sys
class AutomationScheduler:
def __init__(self):
self.jobs = []
self.running = True
# 优雅退出
signal.signal(signal.SIGINT, self._signal_handler)
signal.signal(signal.SIGTERM, self._signal_handler)
def _signal_handler(self, signum, frame):
print("\n🛑 收到终止信号,正在安全退出...")
self.running = False
def add_daily_job(self, job_func, time_str: str, *args, **kwargs):
"""添加每日定时任务"""
job = schedule.every().day.at(time_str).do(job_func, *args, **kwargs)
self.jobs.append(job)
print(f"⏰ 已添加每日任务: {job_func.__name__} @ {time_str}")
return job
def add_interval_job(self, job_func, minutes: int, *args, **kwargs):
"""添加间隔任务"""
job = schedule.every(minutes).minutes.do(job_func, *args, **kwargs)
self.jobs.append(job)
print(f"⏰ 已添加间隔任务: {job_func.__name__} 每 {minutes} 分钟")
return job
def run(self):
"""启动调度循环"""
print("🚀 自动化调度器已启动,按 Ctrl+C 停止")
while self.running:
schedule.run_pending()
time.sleep(1) # 每秒检查一次,避免 CPU 空转
# 示例任务函数
def daily_backup():
print(f"[{time.strftime('%H:%M:%S')}] 执行数据备份...")
def health_check():
print(f"[{time.strftime('%H:%M:%S')}] 执行健康检查...")
# 启动示例
# scheduler = AutomationScheduler()
# scheduler.add_daily_job(daily_backup, "02:00")
# scheduler.add_interval_job(health_check, 30)
# scheduler.run()
6.2 跨平台部署为系统服务
Linux (systemd):
创建 ~/.config/systemd/user/automation.service:
[Unit]
Description=Personal Python Automation
After=network.target
[Service]
Type=simple
ExecStart=/home/yourname/automation-env/bin/python /home/yourname/automation/main.py
Restart=always
RestartSec=10
[Install]
WantedBy=default.target
启用命令:
systemctl --user enable automation.service
systemctl --user start automation.service
Windows (任务计划程序):
使用 PowerShell 快速创建:
$action = New-ScheduledTaskAction -Execute "python.exe" -Argument "C:\scripts\main.py"
$trigger = New-ScheduledTaskTrigger -Daily -At 9am
Register-ScheduledTask -Action $action -Trigger $trigger -TaskName "PythonAutomation" -Description "Daily automation tasks"
macOS (launchd):
创建 ~/Library/LaunchAgents/com.user.automation.plist,使用 launchctl load 加载。
七、完整实战:每日自动日报系统
将上述能力组合,构建一个完整的自动化工作流:
import os
from datetime import datetime, timedelta
from pathlib import Path
class DailyReportBot:
def __init__(self):
self.report_dir = Path.home() / "Automation" / "Reports"
self.report_dir.mkdir(parents=True, exist_ok=True)
# 从环境变量读取配置
self.email_sender = os.environ.get("EMAIL_USER")
self.email_password = os.environ.get("EMAIL_PASS")
self.manager_email = os.environ.get("MANAGER_EMAIL")
def collect_data(self) -> list:
"""模拟数据收集,实际可对接数据库/API"""
yesterday = (datetime.now() - timedelta(days=1)).strftime("%Y-%m-%d")
return [
[yesterday, "核心系统", 32000, 15000, "", "稳定运行"],
[yesterday, "客户端App", 18000, 8000, "", "发布v2.1"],
[yesterday, "数据平台", 0, 5000, "", "集群扩容"],
]
def generate_report(self) -> str:
"""生成日报文件"""
today = datetime.now().strftime("%Y%m%d")
filename = self.report_dir / f"daily_report_{today}.xlsx"
data = self.collect_data()
create_formatted_report(data, str(filename), title=f"日报 {today}")
return str(filename)
def send_notification(self, attachment: str):
"""发送邮件通知(此处复用前文 send_email 函数)"""
if not all([self.email_sender, self.email_password, self.manager_email]):
print("⚠️ 邮件配置不完整,跳过发送")
return
subject = f"工作日报 {datetime.now().strftime('%Y-%m-%d')}"
body = """
领导,您好:
附件为今日工作日报,请查收。
此邮件由自动化系统发送。
"""
# send_email(subject, body, self.manager_email, attachment) # 复用前文函数
print(f"📧 模拟发送邮件至 {self.manager_email}")
def cleanup_old_reports(self, keep_days: int = 30):
"""清理过期报告"""
cutoff = datetime.now() - timedelta(days=keep_days)
deleted = 0
for file in self.report_dir.glob("daily_report_*.xlsx"):
file_time = datetime.fromtimestamp(file.stat().st_mtime)
if file_time < cutoff:
file.unlink()
deleted += 1
print(f"🧹 清理完成,删除 {deleted} 个过期文件")
def run(self):
"""执行完整流程"""
print(f"🤖 日报机器人启动 @ {datetime.now()}")
try:
# 1. 整理环境
self.cleanup_old_reports()
# 2. 生成报表
report_path = self.generate_report()
# 3. 发送通知
self.send_notification(report_path)
print("✅ 日报流程全部完成")
except Exception as e:
print(f"❌ 流程异常: {e}")
# 此处可接入错误告警(如钉钉机器人)
# 定时调度入口
def daily_job():
bot = DailyReportBot()
bot.run()
# 生产环境使用
# scheduler = AutomationScheduler()
# scheduler.add_daily_job(daily_job, "18:00")
# scheduler.run()
八、踩坑与最佳实践
| 问题 | 解决方案 |
|---|---|
| 脚本在后台运行一段时间后崩溃 | 添加 try/except 捕获异常,配合 logging 记录错误,而非直接 print |
| 定时任务时间漂移 | 使用 schedule 的 run_pending() 配合短间隔 sleep,或改用系统级 Cron/systemd |
| Selenium 被反爬检测 | 开启 --headless,使用 undetected-chromedriver 库,或模拟真实鼠标轨迹 |
| 邮件发送被服务商拦截 | 使用应用专用密码(App Password),开启 SMTP 服务,避免高频发送 |
| 路径硬编码导致跨平台失败 | 统一使用 pathlib.Path,避免字符串拼接路径 |
| 敏感信息泄露 | 绝对不要提交密码到 Git,使用 .env 文件 + python-dotenv |
九、进阶方向
当你掌握了基础自动化后,可以探索以下方向:
- GUI 自动化:使用
PyAutoGUI或Lackey处理无法通过 API 操作的老旧系统; - RPA 增强:结合
Playwright进行无头浏览器自动化,比 Selenium 更稳定; - 消息推送:集成企业微信/钉钉/Slack Webhook,实现即时通知;
- 云部署:将脚本部署到云服务器或树莓派,实现 7×24 小时运行;
- 低代码平台:使用
Prefect或Airflow管理复杂的工作流依赖。
十、结语
自动化不是一蹴而就的,而是持续迭代的过程。建议从「最让你烦恼的一个重复任务」入手,先写一个 20 行的小脚本,再逐步扩展。
记住两个原则:
- 先跑起来,再优化:不要追求一次性完美,先解决有无问题;
- 可观测性优先:任何自动化脚本都必须有日志和异常通知,否则你只会知道它「什么时候坏了」,而不知道「为什么坏」。
希望本文能成为你个人自动化之旅的起点。如果你实现了有趣的自动化场景,欢迎在评论区分享。
参考链接:
本文代码在 Python 3.11+ 环境测试通过,最后更新于 2026 年 6 月。
更多推荐

所有评论(0)