资讯详情

10个Python自动化脚本:从文件整理到定时备份的效率工具箱

📅 2026/10/13 8:19:19 | 华诺云谱 👁 阅读
10个Python自动化脚本:从文件整理到定时备份的效率工具箱
大概在两年前我第一次在半夜十二点盯着屏幕上几十个待整理的文件发呆时产生了一个非常原始的念头“这种破事能不能别让我亲手干”。后来我陆陆续续写了几十个Python自动化脚本从最开始的下载文件夹整理到后来的报表合并、网页监控、定时备份说实话脚本带来的最大改变不是省了多少时间而是让我把大量重复的脑力劳动彻底外包了出去。今天这篇就聊一聊我反复在用、也反复踩过坑以后保留下来的10个Python自动化脚本。它们覆盖了文件处理、办公文档、信息采集、系统维护、数据库导出这几个最常见的场景特别适合刚接触自动化、想用Python解决日常琐事的同学也适合已经写了几段脚本但想看看别人怎么组织代码的同行。写这些脚本有一个很朴素的原则一次只解决一个问题而且必须能反复运行而不出乱子。很多所谓的“自动化脚本”跑一次就崩原因往往不是功能没用而是没有考虑重复执行时的状态问题。这篇文章里我会把每个脚本的功能、核心代码、使用方式、以及实际踩过的坑全部摊开讲代码可以拷走改改就用。1. 动手之前先想明白自动化脚本要解决的是什么1.1 软件里的“体力活”最值得自动化我观察了身边很多人的日常大部分时间其实不是花在写复杂的业务逻辑上而是花在“搬数据”、“整理文件”、“同步信息”这些软件里的体力活上。比如把好几个Excel表里的数据复制到一个总表把项目目录里上百个图片从PNG转成JPG把每天生成的日志文件按日期归档再把关键报表定时发到指定邮箱。这类任务有一个共同特征规则明确、步骤固定、重复频率高。只要规则明确就可以用代码描述只要步骤固定就可以安全执行只要重复频率高自动化就值得投入时间。我个人的判断标准是如果一个操作每天超过5分钟或者每周要做超过3次那就值得写脚本。哪怕写脚本花了一个小时只要它能在未来一个月里每天帮你省下5分钟这笔账就不亏。而且写脚本的过程中你会被迫把操作流程拆解得非常清晰这反过来也会提升你对这些重复事务本身的理解。1.2 脚本设计的三条核心原则第一条是无脑可运行原则。脚本不能依赖一个复杂的上下文最好做到直接双击或者一条命令就能跑所有参数都能通过配置文件或者命令行传进去。第二条是幂等原则。同一个脚本跑一遍和跑十遍结果应该是一样的。比如移动文件之前先检查目标位置是否已经存在同名文件否则第二次运行的时候就会覆盖掉之前的结果。第三条是可观察原则。脚本运行完要留下日志至少要有清楚的输出让用户知道它到底做了什么、有没有失败。很多脚本的“事故”都不是逻辑错了而是失败了没有任何提示等发现的时候数据已经被弄乱了。1.3 标准库优先按需引入第三方库这里多说一句选型问题。我能用标准库解决的绝不引入第三方库。原因很实在标准库不需要安装环境拿到任何机器上都是干干净净的也没有版本冲突问题。只有当标准库明确覆盖不了需求时我才会考虑第三方库。比如操作图片必须用Pillow合并PDF我用pypdf处理Excel大规模数据我用pandas这些都是领域内公认的成熟方案。具体选哪一版我一般会固定版本号并写进requirements文件里而不是随手pip install最新版这样换机器部署时才能复现同样的环境。2. 环境准备与脚本的通用骨架2.1 虚拟环境与依赖清单在写第一个正式脚本前先把环境搭好。我习惯用venv来隔离依赖每个自动化项目一个目录内部结构也很简单my_automation/ ├── venv/ ├── scripts/ │ ├── organize_files.py │ ├── combine_excel.py │ └── ... ├── config/ │ └── config.yaml ├── logs/ │ └── run.log └── requirements.txt虚拟环境的创建和执行命令就三行python -m venv venv source venv/bin/activate # Windows下用 venv\Scripts\activate pip install -r requirements.txtrequirements.txt里写明用到的第三方库和版本比如pandas、pypdf、Pillow、requests、qrcode等等。我不会把一个项目里所有脚本的依赖全堆在一起还是会按实际用途分组维护避免给后面新增脚本造成污染。2.2 脚本运行入口怎么设计比较顺手每一个脚本我都会设计一个统一的入口。命令行参数用argparse或者直接读取配置文件都行但我不喜欢把配置硬编码在脚本里。比如说要整理的目标目录、要排除的文件类型、是否删除重复项这些都应该放在配置文件里。当多个脚本共享同一套配置时再用一个config.py去加载它很方便。保持脚本的独立性也很重要。10个脚本之间尽量不要互相import每个脚本都能独立运行。即使它们处理的是同一批文件各自的职责边界也要清楚一个只负责整理一个只负责压缩一个只负责备份。这样后续维护任何一个脚本都不会牵连到其他功能。2.3 一个我写脚本时必加的日志模板很多初学的人会写一大串print然后就不管了但脚本挂在定时任务里的时候print根本没人看。我习惯在脚本里内嵌一个简单的日志配置输出到控制台的同时也输出到日志文件。下面是通用骨架import logging from datetime import datetime logger logging.getLogger(auto_task) logger.setLevel(logging.INFO) fmt logging.Formatter(%(asctime)s %(levelname)s %(message)s) sh logging.StreamHandler() sh.setFormatter(fmt) fh logging.FileHandler(flogs/run_{datetime.now().strftime(%Y%m%d)}.log, encodingutf-8) fh.setFormatter(fmt) logger.addHandler(sh) logger.addHandler(fh)这样不管脚本是手动跑还是定时跑出了问题都可以去翻当天的日志文件。我的习惯是所有可能失败的操作都留下“成功失败”的标记比如文件移动前后各打一条信息配合结果校验。脚本运行完以后再看一眼日志心里就稳定多了。3. 十个脚本逐个拆解功能、代码与避坑下面进入正题。这10个脚本我按场景分成了四类文件杂物清理、办公文档处理、网络与通知、系统运维辅助。每个脚本单独可用组合起来就是一套完整的个人效率工具箱。3.1 自动整理下载文件夹第一个脚本绝对是最容易带来成就感的。它做的事情很简单扫描下载目录按后缀名把文件分门别类移动到对应的子目录里图片归图片文档归文档压缩包归压缩包。实现方式用pathlib和shutil就够了。import shutil from pathlib import Path CONFIG { source: Path.home() / Downloads, rules: { 图片: [.jpg, .jpeg, .png, .gif, .webp], 文档: [.pdf, .docx, .xlsx, .pptx, .md], 压缩包: [.zip, .rar, .7z, .tar, .gz], 脚本: [.py, .js, .sh], } } def organize(): src CONFIG[source] for file in src.iterdir(): if file.is_dir(): continue for folder, exts in CONFIG[rules].items(): if file.suffix.lower() in exts: target_dir src / folder target_dir.mkdir(exist_okTrue) target target_dir / file.name if target.exists(): target target_dir / f{file.stem}_{file.stat().st_mtime:.0f}{file.suffix} shutil.move(str(file), str(target)) print(f移动: {file.name} - {folder}/) break if __name__ __main__: organize()这个脚本最需要注意的就是同名文件冲突。我第一次跑的时候直接覆盖了一个重名文件因为移动逻辑只写了shutil.move没有处理目标同名的情况。后来我统一在文件名后面追加源文件修改时间戳能用但不太好看如果希望更优雅一点可以在目标文件名后递增序号比如“需求文档_1.pdf”。另外一定要跳过文件夹不然递归移动会把目录结构弄乱。这个脚本适合配合定时任务每天下午执行一次不会让下载文件夹再变成一个混乱的垃圾场。3.2 图片批量压缩与格式转换这个脚本是我帮家里人处理相册时被逼出来的。平时写博客、做PPT、发邮件图片动不动就是好几MB不改一下根本传不出去。用Pillow可以轻松实现批量压缩、尺寸缩放和格式统一。from PIL import Image from pathlib import Path def compress_images(input_dir: Path, output_dir: Path, max_width: int 1920, quality: int 82): output_dir.mkdir(parentsTrue, exist_okTrue) for img_path in input_dir.glob(*.png): with Image.open(img_path) as im: im im.convert(RGB) if im.width max_width: ratio max_width / im.width im im.resize((int(im.width * ratio), int(im.height * ratio))) out_path output_dir / f{img_path.stem}.jpg im.save(out_path, JPEG, qualityquality) print(f已压缩: {img_path.name} - {out_path.name})这里有个关键点PNG转JPG之前必须调用convert(RGB)否则带透明通道的图片会直接报错。我遇到过很多次这种问题所以现在处理图片格式转换时一律先转RGB。压缩质量方面我一般选82这是一个平衡体积与画质的点肉眼基本看不出差别但文件大小可以减小一半以上。如果你处理的是大量产品图或者需要保留透明背景的场景输出格式就改成PNG质量参数改成优化图片调色板而不是靠JPEG压缩。3.3 Excel多表合并工具办公自动化的高频需求里Excel合并一定排前几。平时的场景是一个文件夹里放了几个月的报表每个文件的格式和表头都一样需要汇总到一个总表里。用pandas来处理非常顺手。import pandas as pd from pathlib import Path def merge_excel(src_dir: Path, output_file: Path, suffix.xlsx): frames [] for f in sorted(src_dir.glob(f*{suffix})): if f.name output_file.name: continue df pd.read_excel(f) frames.append(df) print(f读取: {f.name}行数 {len(df)}) if frames: result pd.concat(frames, ignore_indexTrue) result.to_excel(output_file, indexFalse) print(f合并完成总行数: {len(result)})有人会问既然只是多个工作表合并为什么不用Excel自带的功能我的经验是Excel自带的功能处理少量文件、少量数据确实没问题但当文件数量到了几十个、每个文件几十MB时自带的合并功能要么卡死要么格式错乱而且没法重复执行。pandas的concat既稳定又快速数据量上千行也毫无压力。唯一的坑是读取Excel时pandas默认使用openpyxl引擎所以要先装好openpyxl。如果文件里有不同列名concat时默认会按列名对齐但我个人建议合并前先统一表头否则出来的结果里同一字段会出现两列情况特别难看。3.4 PDF批量合并与拆分PDF处理属于典型的“日常用不到用到时手忙脚乱”。比如把多个扫描件合成一个PDF或者从一个大PDF里抽取若干页发给别人。这里我用pypdf它是原PyPDF2的延续API很清爽。from pypdf import PdfReader, PdfWriter from pathlib import Path def merge_pdfs(pdf_list: list, output_file: str): writer PdfWriter() for pdf_path in pdf_list: reader PdfReader(pdf_path) for page in reader.pages: writer.add_page(page) print(f添加: {Path(pdf_path).name}共 {len(reader.pages)} 页) with open(output_file, wb) as f: writer.write(f) print(f合并完成总页数: {len(writer.pages)})这个脚本最大的坑是加密PDF。很多从扫描仪或者某些工具生成的PDF默认带权限限制直接读取会报错。遇到这种情况先确认是不是需要密码如果需要密码就要在PdfReader里传入密码参数。更坑的是一些PDF页面中的字体编码不规范用pypdf合并后页面文字会乱码这个真没有通用的解法我的建议是原文件能转就转成图片再合并虽然文件变大但不会出乱子。我平时更多是用这个脚本来合并扫描件扫描件本身是图片合并之后完全不会有字体问题效果很稳定。3.5 批量重命名工具规则先行批量重命名这个功能以后缀名替换、加前缀、编号补零、日期批量加上为主。看起来简单但正因为在文件名上犯过错误我才写了个带预演功能的版本。from pathlib import Path def rename_files(target_dir: Path, prefix: str , replace_from: str , replace_to: str ): for file in target_dir.iterdir(): if file.is_dir(): continue new_name file.name if replace_from: new_name new_name.replace(replace_from, replace_to) if prefix: new_name prefix new_name new_path file.with_name(new_name) if new_path.exists(): print(f跳过: {file.name} - {new_name} 已存在) continue file.rename(new_path) print(f重命名: {file.name} - {new_name})我特别想强调的是“预演”这个习惯。实际生产里重命名的场景常配合其他文件整理动作一旦执行错了很难回退。所以我建议在此基础上增加一个--dry-run参数先打印出所有将要执行的改名操作让用户确认一遍再真正执行。这个习惯后来延伸到所有有破坏性操作的脚本上先计划再执行中间留一道人工确认。不要小看这一道确认它能拦下九成以上的低级错误。3.6 定时网页内容监控这个脚本使用requests请求目标接口获取数据再和上一次运行时的结果做对比如果发生变化就发送通知。常见的应用场景是监控某些页面里更新的内容、价格变化、或者后台接口的状态码。import requests import json def check_url(url: str, state_file: str): resp requests.get(url, timeout10) current resp.text try: with open(state_file, r, encodingutf-8) as f: last f.read() except FileNotFoundError: last if current ! last: with open(state_file, w, encodingutf-8) as f: f.write(current) return True, 内容发生变化 return False, 内容未变化定时监控要注意两点。第一是目标接口或者页面的更新频率请求太频繁会被对方限流甚至封IP所以建议间隔设置在30分钟以上必要时在请求里加上随机的User-Agent。第二是状态文件不能只存一个原始文本存的时候算一个hash值会更快更省空间。这个脚本改成立即通知模式后就成了很多个人项目里重要信息变化提醒的雏形。我把它拆出来单讲是因为这种“请求—对比—通知”的模式几乎能套用所有信息监控场景。3.7 关键文件定时备份备份脚本用shutil实现文件复制和zip归档。我最常用的场景是把一个项目里的源代码目录、配置文件、数据文件打包成一个带时间戳的压缩包然后轮转删除旧备份。import shutil import zipfile from pathlib import Path from datetime import datetime config { backup_targets: [project/src, project/config, project/data], backup_dir: Path(backups), keep_num: 7 } def backup(): backup_dir config[backup_dir] backup_dir.mkdir(exist_okTrue) date_str datetime.now().strftime(%Y%m%d_%H%M%S) zip_path backup_dir / fbackup_{date_str}.zip with zipfile.ZipFile(zip_path, w, zipfile.ZIP_DEFLATED) as zf: for target in config[backup_targets]: p Path(target) if p.exists(): if p.is_dir(): for f in p.rglob(*): if f.is_file(): zf.write(f, f.relative_to(p.parent)) else: zf.write(p, p.name) # 只保留最近 keep_num 个备份 backups sorted(backup_dir.glob(backup_*.zip)) for old in backups[:-config[keep_num]]: old.unlink() print(f备份完成: {zip_path})为什么要用zipfile而不是直接shutil.make_archive其实两者都可以但zipfile让我可以精细控制哪些文件进压缩包、怎么组织目录层级还能排除临时文件。备份的坑主要有三个一是备份目录本身不要被套进备份目标里否则会无限递归膨胀二是在Linux下用cron定时跑时路径必须写成绝对路径否则脚本会因为相对路径找不到文件三是不要只备份不做恢复测试至少每个季度要手动解压一次确认文件没有损坏。这个脚本配合定时计划是我所有脚本里“救人性命”次数最多的一个。3.8 日志文件按大小滚动与清理应用日志和系统日志的磁盘占用问题几乎每个长期运行的服务器都会遇到。很多初学Linux的人第一反应是写一堆shell脚本来清但用Python脚本配合定时任务也能做得很好而且跨平台。脚本的逻辑是扫描指定目录下超过阈值大小的文件把超过保留天数的旧日志先压缩再统一删除更早的。from pathlib import Path import gzip def roll_and_clean(log_dir: Path, max_days: int 30): now datetime.now() for f in log_dir.rglob(*.log): age_days (now - datetime.fromtimestamp(f.stat().st_mtime)).days if age_days max_days: with f.open(rb) as src, gzip.open(str(f) .gz, wb) as dst: dst.write(src.read()) f.unlink() print(f已压缩过期日志: {f.name})这个脚本实际跑起来会遇到一个问题日志文件正被进程占用直接删除会报权限错误。解决的办法是先复制再删除或者干脆跳过正在写入的日志文件。还有一点是要小心rglob递归到某个巨型目录里如果日志目录层级很深、文件数量巨大建议先按目录做白名单。我的实践里会加一条规则只处理直接子文件名的日志不递归进子目录除非明确需要。这样既减少误伤也提高执行效率。3.9 数据库定时导出与汇总数据库导出这个场景在个人项目里非常常见。比如某个商品订单表、某个指标统计表每天需要导出成CSV发给同事或者导入到其他系统。这里以SQLite为例代码很短换成MySQL或者PostgreSQL只是连接串变了。import sqlite3 import csv from pathlib import Path def export_table(db_path: str, table_name: str, output_path: str): conn sqlite3.connect(db_path) cur conn.cursor() cur.execute(fSELECT * FROM {table_name}) rows cur.fetchall() cols [d[0] for d in cur.description] with open(output_path, w, newline, encodingutf-8-sig) as f: writer csv.writer(f) writer.writerow(cols) writer.writerows(rows) print(f导出完成: {table_name}{len(rows)} 行) conn.close()导出CSV时我特别强调编码要用utf-8-sig而不是utf-8因为如果用utf-8不带BOM导出Excel直接打开会乱码这问题困扰过不少人。SQLite本身是单文件数据库导出比较简单如果是MySQL这种服务型数据库注意数据库连接密码不要写在脚本里要用环境变量或者专门的配置文件管理。另外每次导出都建议带上日期后缀避免第二天导出覆盖前一天的成果。3.10 批量生成二维码与管理标签最后一个脚本是我实际用来管理设备的。嵌入式项目里每台设备需要有一个唯一的二维码标签包含设备编号和访问地址。用qrcode库批量生成再把编号文字直接贴到二维码下方输出成一张A4排版好的标签页打印出来就是现成的管理标签。import qrcode from PIL import Image, ImageDraw, ImageFont from pathlib import Path def gen_labels(ids: list, base_url: str, out_dir: Path): out_dir.mkdir(exist_okTrue) for i, device_id in enumerate(ids): qr qrcode.QRCode(versionNone, box_size8, border2) qr.add_data(f{base_url}/{device_id}) qr.make(fitTrue) qr_img qr.make_image(fill_colorblack, back_colorwhite) canvas Image.new(RGB, (qr_img.width, qr_img.height 40), white) canvas.paste(qr_img, (0, 0)) draw ImageDraw.Draw(canvas) draw.text((10, qr_img.height 10), device_id, fillblack) canvas.save(out_dir / flabel_{i:03d}.png)二维码生成的坑点我遇到过两个。第一个是内容太长导致二维码图案过密扫码容易失败解决办法是使用短链接或者在生成前用URL缩短服务。第二个是生成大量图片时文件名记得补零排序这样打印出来的标签顺序才不会跑乱。还有一个工艺上的细节打印出来之后要实际用手机扫一遍再批量打印不要想当然以为生成的二维码一定扫得出来。我曾经生成过一批包含中文内容的二维码不少扫码软件识别不出来后来统一把内容换成拼音和编号才解决。4. 让脚本真正“自动化”起来调度与部署经验脚本写得再漂亮如果每天都要手动运行一次那只能叫半自动化。真正要解放双手还得把这10个脚本挂到系统的定时任务里。4.1 Windows下的任务计划程序Windows定时任务我用任务计划程序创建批处理器选Python解释器的绝对路径参数里写上脚本绝对路径起始目录也填到脚本目录。比如说我的图片压缩脚本每周五下午6点自动跑一次然后通过邮件把结果发给我已经持续运行了很多期。任务计划程序需要注意两个细节一个是“仅在用户登录时运行”这个选项如果电脑锁屏很多任务压根不会执行建议选“不管用户是否登录都要运行”另一个是任务执行完后“运行结果”这一列要定期瞄一眼我遇到过脚本出错但任务一直显示“正在运行”的假象那是脚本进程卡住了。4.2 Linux下的cron定时任务Linux下的定时任务我会写到crontab里格式是大家熟悉的“分 时 日 月 周 命令”。举个例子每天凌晨3点备份数据并清理日志crontab行大概长这样0 3 * * * /usr/bin/python3 /home/user/automation/backup.py /home/user/logs/cron.log 21我强烈建议在crontab里加上日志重定向不然脚本的print输出会直接丢掉出了问题查起来非常痛苦。还有一个习惯是把脚本中所有路径都写成绝对路径。因为cron执行时的工作目录通常是调用者的home目录如果脚本里用了相对路径十有八九会找不到文件。这个是我真实吃过的亏印象很深。4.3 任务目录规划与依赖管理脚本多了以后被不同任务调用就开始混乱。我的方案是每个脚本设置一个规范的头部注释把用途、入参、输出、依赖库写全。脚本内统一使用__file__来定位项目根目录而不要依赖当前工作目录。这样无论从哪个目录发起调用脚本都能正确找到配置文件和日志目录。依赖管理上我会在每次新增第三方库之后重新生成requirements.txt避免几个月后部署新机器时缺这缺那。5. 运行过程中排查问题的高频经验自动化脚本部署之后最怕的就是挂了不知道。下面几类问题是我在长时间运行中遇到最多、也最有排错价值的。5.1 路径和编码问题这方面出现频率最高的就是Windows下中文路径和脚本里的中文注释导致的编码问题。Python 3虽然默认UTF-8但Windows控制台的默认编码是GBK一旦print输出中文经常直接抛UnicodeEncodeError。解决方法可以在脚本最顶部加import sys; sys.stdout.reconfigure(encodingutf-8)或者在环境变量里设置PYTHONIOENCODINGutf-8。至于路径Excel、PDF、图片文件如果名字里带特殊符号建议在处理前统一规范化路径用Path对象而不是手写字符串拼接。5.2 依赖库版本冲突的灵异事件我遇到过很多次“昨天还能跑今天莫名其妙崩了”的情况十有八九是第三方库被自动升级了。所以我把所有自动化脚本的依赖都固定在requirements.txt里而不是永远依赖最新版。安装的时候用pip install -r requirements.txt升级什么库、什么时候升级由我自己控制。如果想省心一点还可以给整个项目写一个启动脚本先检查关键库的版本不符合再提醒。5.3 脚本被多次重复执行的并发踩踏有段时间某台机器的定时任务因为任务积压同一个备份脚本被同时跑了两次两个进程同时写同一个备份目录结果备份文件全乱了。后来我在脚本里统一加了一个文件锁用fcntl在Linux下锁住一个临时文件如果锁拿不到就直接退出。Windows下可以用msvcrt做类似的逻辑。这个防护看起来多余但它能避免几乎所有的“任务重叠执行”事故。6. 脚本写多了之后的几点感悟自动化脚本这个事执行起来门槛不高但要做好真的需要比别人多想一步。写第1个脚本时我喜欢一个脚本解决所有问题写多了之后反而喜欢拆得越小越好。一个脚本只做好一件事组合起来调用维护成本和可复用性会有本质的区别。另一个变化是我开始花更多时间把脚本变成一种服务比如把自动整理下载文件夹的脚本和邮件通知组合在一起晚上让它把文件整理报告发到邮箱第二天早上看下结果就行完全不用手动打开终端。最后分享一个我保存了很久的小技巧不要在脚本里用一堆“魔法数字”。每次要改参数时还得翻代码找效率很低。正确做法是统一挂载到配置文件里需要调整时只改配置脚本代码保持稳定。这个习惯帮了我大忙因为很多脚本是几个月前写的等再修改时看到清晰配置比我努力回忆代码意图舒服太多了。自动化脚本一定会越写越多也会越写越少。越写越多是因为会不断发现新的重复劳动可以被替代越写越少是因为最终会沉淀出一套稳定、强大、可复用的核心工具普通任务换个参数就能跑不再需要从头造轮子。这个过程本身就是学习Python最划算的一条路。
📝

华诺云谱内容团队

资深建站顾问 · 行业研究员

10年+企业数字化服务经验,专注智能建站、SEO优化与品牌营销,持续输出建站技巧、行业洞察与营销干货,已帮助5000+企业实现数字化增长。

你可能需要的服务

订阅华诺云谱资讯周报

每周一封,精选建站技巧、SEO与营销干货,直达邮箱。已有 8,000+ 企业主订阅,助你少走弯路。

↑