ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

10个实用Python自动化脚本,让重复工作一键完成

10个实用Python自动化脚本,让重复工作一键完成 每天上班打开电脑第一件事就是把这些重复劳动交给脚本整理下载文件夹、合并带格式的Excel表、重命名一批照片、检查服务器日志有没有爆掉。说实话我写Python自动化脚本不是为了炫技纯粹是被逼的——同样的操作每周要做三五次手点鼠标点到怀疑人生。这篇东西把我这几年真正用得上、真正省了时间的10个脚本整理出来都是短小精悍、改改就能用的那种不求什么高大上的架构只求跑起来稳效果直观。文中的代码统一用Python 3.8编写第三方库尽量少依赖环境装不好的朋友可以直接看第1节里面有踩坑经验。不管你是刚学Python没几天的新手还是每天和Excel、文件、报表打交道的办公党又或者是刚接触自动化测试的测试工程师这几个脚本都能帮你“偷”出不少时间。每个脚本我会直接贴出核心代码、解释它解决什么问题再补几句我在实际使用中总结的注意事项。有些脚本看起来简单但细节处藏着大坑我会把这些坑单独拎出来说清楚。1. 写自动化脚本之前先把环境收拾利索很多人写了脚本跑不起来90%的问题出在环境上而不是代码本身。所以我不急着贴脚本先说几句环境配置这部分对新手尤其重要。我的建议是Windows上直接去Python官网下载安装包安装时务必勾选“Add Python to PATH”这个选项否则装完在命令行输python会提示找不到命令。装好之后打开命令行输入python --version能显示版本号就说明基础环境没问题了。macOS和Linux系统一般自带Python但版本可能偏旧。我建议用python3命令来调用因为系统自带的python往往是指向Python 2的软链接。如果要用第三方库最好先建一个虚拟环境避免把系统环境搞乱。虚拟环境建起来很简单在项目目录下执行python -m venv venv然后激活它Windows下运行venv\Scripts\activatemacOS和Linux下运行source venv/bin/activate。激活后命令行前面会出现(venv)字样这时候pip install装的包都只属于这个项目互不干扰。1.1 第三方库的安装与版本锁定我列的这10个脚本里大部分只用Python标准库但有几个功能比如Excel合并、PDF处理、图片压缩标准库搞不定必须装第三方库。安装方式就一条命令pip install pandas openpyxl。同时装的库多了要注意版本冲突所以我推荐在项目里维护一个requirements.txt文件把用到的库和版本号都记录进去。生成方式很简单在激活虚拟环境后执行pip freeze requirements.txt下次换电脑或同事要复现时直接pip install -r requirements.txt一键装齐。这里要说一个我踩过的坑pandas这个库在Windows上有时会因为缺少VC运行库而安装失败或导入报错报错信息一般是ImportError: DLL load failed。解决办法是先装Microsoft Visual C Redistributable或者直接用pip install pandas的预编译轮子版本普通用户基本不需要自己编译源码。2. 十个高频自动化脚本与核心代码拆解下面进入正题。我按使用频率从高到低排列每个脚本都给出可直接运行的代码和解释。所有代码我都尽量精简去掉花里胡哨的部分保留干活的骨架。没用到的功能我就删掉因为多余的功能意味着多余的维护成本。2.1 下载文件夹自动整理脚本我的“下载”文件夹常年是重灾区安装包、PDF文档、图片、压缩包混在一起每次找文件都要翻半天。这个脚本的作用是把下载目录里的文件按扩展名自动归类到对应子文件夹比如图片、文档、压缩包、安装包、其他。import os import shutil from pathlib import Path DOWNLOAD_DIR Path.home() / Downloads SUFFIX_MAP { 图片: [.jpg, .jpeg, .png, .gif, .webp], 文档: [.pdf, .docx, .doc, .xlsx, .txt, .md], 压缩包: [.zip, .rar, .7z, .tar, .gz], 安装包: [.exe, .msi, .dmg, .pkg], 代码: [.py, .js, .ts, .java, .cpp, .html, .css], } def auto_organize(): # 先建好所有分类目录shutil.move会自动创建目标路径 for category in SUFFIX_MAP: (DOWNLOAD_DIR / category).mkdir(exist_okTrue) # 遍历目录下的文件忽略子目录和脚本自身 for file in DOWNLOAD_DIR.iterdir(): if not file.is_file() or file.name __file__: continue moved False for category, suffixes in SUFFIX_MAP.items(): if file.suffix.lower() in suffixes: shutil.move(str(file), str(DOWNLOAD_DIR / category / file.name)) moved True break if not moved: shutil.move(str(file), str(DOWNLOAD_DIR / 其他 / file.name)) if __name__ __main__: auto_organize()这段代码逻辑不复杂核心就是遍历目录里的每个文件通过file.suffix拿到扩展名再和字典里的映射做匹配。我特意加了file.name __file__的判断防止脚本把自身当作垃圾文件移走。另外Path对象是Python 3.4以后推荐的文件路径写法比老式的os.path.join更简洁处理跨平台路径时也不会出错。实际使用时我建议在Windows任务计划程序或macOS的launchd里配置成每天凌晨执行一次效果最好。注意一点shutil.move在跨磁盘移动时会先复制再删除速度会比较慢所以如果你把下载目录放在了C盘但目标文件夹在D盘移动大量文件时会明显卡顿。这个场景下的优化方案是改用os.replace但它不支持跨设备权衡后我还是认为shutil.move更稳妥。2.2 Excel多表合并脚本做数据整理的同事每天有一半时间花在合并Excel上各分店发来格式相同的报表需要合并成一个总表。用pandas简直是降维打击十几行代码搞定。我见过很多人还在手动复制粘贴那个效率真的不忍直视。下面这个脚本可以合并同一个文件夹下所有.xlsx文件并且保留每个表里相同的列。import pandas as pd from pathlib import Path DATA_DIR Path(data) # 存放各分店Excel的目录 OUTPUT_FILE 合并结果.xlsx def merge_excel(): all_data [] for file_path in DATA_DIR.glob(*.xlsx): # 用pd.read_excel读取sheet_nameNone表示读取所有工作表 df pd.read_excel(file_path, sheet_nameNone) for sheet_name, sheet_df in df.items(): # 增加一列来源信息方便追溯 sheet_df[来源文件] f{file_path.name}:{sheet_name} all_data.append(sheet_df) if not all_data: print(目录下没有找到任何Excel文件) return merged pd.concat(all_data, ignore_indexTrue) # 千行以内的数据直接写Excel用openpyxl引擎 merged.to_excel(OUTPUT_FILE, indexFalse) print(f合并完成共{len(merged)}行输出到{OUTPUT_FILE}) if __name__ __main__: merge_excel()这段代码里有个细节值得展开说明pd.read_excel(file_path, sheet_nameNone)返回的是一个字典键是工作表名值是对应的DataFrame。为什么不直接指定sheet_name0读第一个工作表因为很多Excel文件有多个Sheet漏读会导致数据不完整。加上来源文件列是我在实际使用中强烈推荐的一旦合并后发现某个数字对不上你能很快定位到是哪家公司哪个Sheet来的数据省去全表排查的麻烦。合并后写文件时to_excel默认使用的引擎是openpyxl如果没有安装会报错。所以这个脚本装依赖时一定要带上pip install pandas openpyxl。还有一点读Excel的老文件.xls格式需要另一个引擎xlrd但考虑到现在新文件基本都是.xlsx我脚本里就用glob(*.xlsx)来屏蔽老格式。2.3 批量重命名照片脚本相机导出的照片文件名通常是IMG_20250101_123456.jpg这种格式包含信息但不够直观。我习惯把照片按“日期-序号”的方式重命名比如2025-01-01_01.jpg。另外还有一种常见需求把同一目录下的所有文件统一加上前缀。这个脚本我做了两个功能优先按拍摄时间重命名没有拍摄时间的就按文件修改时间。import os from pathlib import Path from datetime import datetime PHOTO_DIR Path(photos) def rename_photos(): files [f for f in PHOTO_DIR.iterdir() if f.is_file()] # 先按修改时间排序否则顺序是乱的 files.sort(keylambda x: x.stat().st_mtime) for index, file in enumerate(files, start1): # 尝试读Exif信息中的拍摄时间读不到就用文件修改时间 timestamp file.stat().st_mtime try: import exifread with open(file, rb) as f: tags exifread.process_file(f) if EXIF DateTimeOriginal in tags: timestamp datetime.strptime( str(tags[EXIF DateTimeOriginal]), %Y:%m:%d %H:%M:%S ).timestamp() except ImportError: pass dt datetime.fromtimestamp(timestamp) new_name f{dt.strftime(%Y-%m-%d)}_{index:02d}{file.suffix.lower()} new_path file.with_name(new_name) if file ! new_path: os.rename(file, new_path) print(f{file.name} - {new_name}) if __name__ __main__: rename_photos()这个脚本默认依赖只有标准库但它会尝试读取Exif拍摄时间如果能读到重命名结果会更精确不会因为文件被复制过而丢失原始拍摄信息。我用了exifread这个轻量库pip install exifread就能装。如果没装代码里的ImportError会被捕获自动回退到文件修改时间。重命名最容易出的问题就是命名冲突。比如你整理一个文件夹里面已经有2025-01-01_01.jpg了再执行脚本会把现有文件覆盖掉。我在代码里没有处理这个情况是因为我默认这个脚本只对“没整理过”的目录生效。如果你要反复执行建议在脚本里加一行检查确认目标文件名不存在时才执行。这个属于自定义扩展不展开写了。2.4 日志文件压缩归档脚本服务器上跑的应用每天都生成日志一个月下来能攒几个GB。日志文件又不能随便删万一要排查历史问题呢。折中方案就是定期压缩归档超过30天的日志文件压缩成.tar.gz再按月份归类磁盘占用能省80%以上。import shutil from pathlib import Path from datetime import datetime, timedelta LOG_DIR Path(logs) ARCHIVE_DIR Path(logs_archive) MAX_AGE_DAYS 30 def archive_logs(): ARCHIVE_DIR.mkdir(exist_okTrue) cutoff datetime.now() - timedelta(daysMAX_AGE_DAYS) cutoff_ts cutoff.timestamp() for file in LOG_DIR.iterdir(): if not file.is_file(): continue # 文件超过30天未修改就进行归档 if file.stat().st_mtime cutoff_ts: month_str datetime.fromtimestamp(file.stat().st_mtime).strftime(%Y-%m) month_dir ARCHIVE_DIR / month_str month_dir.mkdir(exist_okTrue) # 将文件压缩并移动到归档目录 archive_name month_dir / (file.name .tar.gz) with tarfile.open(archive_name, w:gz) as tar: tar.add(file, arcnamefile.name) file.unlink() # 压缩成功后删除原文件 print(f{file.name} 已归档到 {archive_name}) if __name__ __main__: archive_logs()注意这段代码里有几个细节。第一我用tarfile模块而不是shutil.make_archive是因为tarfile可以逐个添加文件并自定义归档名更适合循环处理。第二压缩完成后必须file.unlink()删除原文件否则脚本每次运行都会重复压缩已经归档的文件。第三判断文件新旧用的st_mtime是最后修改时间对日志文件来说基本等于最后写入时间。很多人在这一步会踩坑日志文件正在被应用写入你直接压缩或删除会导致写入异常。我的处理方式是在归档前先调应用接口通知它切分日志文件或者直接在配置里启用“按日切分日志”这样归档脚本只处理昨天的日志文件不会影响正在写的文件。2.5 网页自动化测试冒烟脚本连续几版上线出问题之后我养成了一个习惯每次发版前先跑一遍冒烟测试。说白了就是用脚本自动检查核心页面是否返回正常状态码、关键关键词是否出现在页面里。不依赖测试框架一个纯requests脚本就够了适合没有专门测试环境的团队。import requests # 核心检查清单(页面名称, URL, 应包含的关键词) PAGES [ (首页, https://example.com/, 欢迎), (登录页, https://example.com/login, 用户名), (列表页, https://example.com/list, 数据), ] def smoke_test(): failed [] for name, url, keyword in PAGES: try: resp requests.get(url, timeout10) if resp.status_code ! 200: failed.append(f{name}: HTTP {resp.status_code}) elif keyword not in resp.text: failed.append(f{name}: 缺少关键词 {keyword}) else: print(f{name}: 通过) except requests.RequestException as e: failed.append(f{name}: 请求异常 {e}) if failed: print(冒烟测试失败项) for item in failed: print(f - {item}) raise SystemExit(1) print(全部通过可以发布) if __name__ __main__: smoke_test()这个脚本虽然简单但解决了“没人做回归测试”的痛点。只要把页面清单和关键词维护好发版前跑一遍比人肉打开浏览器一个个点要快得多而且不会因为看漏而漏检。如果项目已经引入了真正的自动化测试框架比如Selenium或Playwright还可以把这段逻辑嵌入到测试套件里作为冒烟测试的第一层防线。维护上要注意的是页面关键词不能选那种经常变动的元素比如带时间戳或用户名的提示语否则脚本会频繁误报。我选的关键词都是标题、页脚版权声明这类相对稳定的内容。另外添加timeout10参数很有必要之前我没加有一次页面挂起导致脚本卡了5分钟才超时。2.6 定时发送报表邮件脚本每当Excel合并脚本跑完下一个动作就是发邮件给团队。用yagmail这个库发送邮件的代码量能被压到极致。不过yagmail在部分企业邮箱环境下会被拦截所以在公司场景我还是推荐用标准库的smtplib更稳妥通用性更强。import smtplib from email.mime.text import MIMEText from email.mime.multipart import MIMEMultipart from email.header import Header from pathlib import Path SMTP_HOST smtp.example.com SMTP_PORT 465 USERNAME senderexample.com PASSWORD your_password # 建议用授权码别用登录密码 def send_mail(subject, body, to_list, attach_pathNone): msg MIMEMultipart() msg[From] USERNAME msg[To] , .join(to_list) msg[Subject] Header(subject, utf-8) msg.attach(MIMEText(body, plain, utf-8)) if attach_path: attach_file Path(attach_path) if attach_file.exists(): part MIMEText(attach_file.read_bytes(), base64, utf-8) part[Content-Type] application/octet-stream part[Content-Disposition] fattachment; filename{attach_file.name} msg.attach(part) # 用SSL连接SMTP服务器465端口 with smtplib.SMTP_SSL(SMTP_HOST, SMTP_PORT) as server: server.login(USERNAME, PASSWORD) server.sendmail(USERNAME, to_list, msg.as_string()) if __name__ __main__: send_mail( subject周报数据汇总, body见附件请查收。, to_list[bossexample.com, teamexample.com], attach_path合并结果.xlsx )这里有几个非常关键的细节。第一MIMEText构造附件时base64要和utf-8配合使用否则中文内容是乱码。第二发件人密码这一行很多邮箱要求用“授权码”而不是登录密码比如网易邮箱、QQ邮箱都在设置里专门生成授权码。第三如果公司邮箱走587端口且要求STARTTLS就不要用SMTP_SSL改用SMTP方法再调用server.starttls()。我写过一段判断逻辑做了兼容但为了代码简洁这里没有放进去。定时发送配合第3节的定时任务配置可以达到“每天早上9点自动发送昨日数据报表”的效果。另外实际生产环境我不会把密码明文写在脚本里而是放在环境变量或独立的配置文件里脚本用os.getenv()读取这样即使代码被别人看到也不会泄露邮箱密码。2.7 PDF合并与抽取文字脚本PDF处理是办公自动化的高频需求合并多份PDF为一份或者从一堆PDF里抽取指定文字用于归档。下面这段代码用PyPDF2实现合并同时用pdfplumber抽取文字。两个库各有擅长合并用PyPDF2足够抽取文字用pdfplumber更准。import os from pathlib import Path PDF_DIR Path(pdfs) MERGED_FILE 合并文件.pdf def merge_pdfs(): from PyPDF2 import PdfReader, PdfWriter writer PdfWriter() for pdf_file in sorted(PDF_DIR.glob(*.pdf)): reader PdfReader(str(pdf_file)) for page in reader.pages: writer.add_page(page) print(f已加入: {pdf_file.name}) with open(MERGED_FILE, wb) as out: writer.write(out) print(f合并完成总页数: {len(writer.pages)}) def extract_text_from_pdf(pdf_path): import pdfplumber texts [] with pdfplumber.open(pdf_path) as pdf: for page in pdf.pages: page_text page.extract_text() if page_text: texts.append(page_text) return \n.join(texts) if __name__ __main__: merge_pdfs() # 示例抽取第一页的文字并在屏幕上打印 text extract_text_from_pdf(MERGED_FILE) print(text[:500])用PyPDF2合并时注意不同版本的API差异较大。老版本的写法是PdfFileReader和PdfFileWriter3.0之后改成了PdfReader和PdfWriter。网上一搜会搜到大量过时代码照着粘贴会直接报错AttributeError: module PyPDF2 has no attribute PdfFileReader这个坑很多人踩过。解决方式很简单要么升级代码写法要么把PyPDF2固定安装到2.x版本。抽取文字用pdfplumber的原因是它对扫描版PDF和复杂版面支持更好。但如果你遇到的是纯扫描图片PDF里面根本没有文字层那任何库都抽不出文本得先用OCR。这个情况我遇到过好几次扫描盖章文件全是图像。这种情况要么用pytesseract配OCR识别要么就用人工处理没有银弹。2.8 图片批量压缩与格式转换脚本运营同事天天要压缩图片才能传后台一张张用PS处理太费劲。用Pillow批量处理可以一次性把所有图片压缩到指定宽度并统一转为JPEG格式。这个脚本我用了好久稳定可靠。from PIL import Image from pathlib import Path IMG_DIR Path(images) OUTPUT_DIR Path(images_compressed) TARGET_WIDTH 1280 # 目标宽度高度自动等比例缩放 QUALITY 80 # JPEG质量100最佳80比较平衡 def compress_images(): OUTPUT_DIR.mkdir(exist_okTrue) for img_file in IMG_DIR.iterdir(): if img_file.suffix.lower() not in (.jpg, .jpeg, .png, .bmp, .webp): continue with Image.open(img_file) as img: # 处理EXIF方向信息避免照片被转置 img ImageOps.exif_transpose(img) # 等比缩放 ratio TARGET_WIDTH / img.width new_height int(img.height * ratio) img img.resize((TARGET_WIDTH, new_height), Image.LANCZOS) # 统一转RGB并保存为JPEG if img.mode ! RGB: img img.convert(RGB) output_path OUTPUT_DIR / (img_file.stem .jpg) img.save(output_path, JPEG, qualityQUALITY, optimizeTrue) print(f{img_file.name} - {output_path.name}) if __name__ __main__: compress_images()这个脚本里有三个容易忽略的坑。第一个是ImageOps.exif_transpose(img)这个函数专门处理照片的EXIF方向信息。手机和相机拍的照片自带方向标记如果不处理压缩后打开会发现图片转了90度。第二个是模式转换PNG图片有透明通道保存为JPEG前必须转换到RGB模式否则save会抛异常。第三个是Image.LANCZOS重采样算法它比默认的NEAREST质量高很多尤其在缩小图片时边缘更平滑。这三个坑我都踩过写进注释里帮大家避开。还有一个建议压缩质量设为80时肉眼基本看不出画质损失文件大小却能减少60%以上。如果你的图片是要放网页上的用85就够了要打印的话建议95不过体积会大不少。2.9 JSON数据定时抓取并生成日报脚本很多内部系统提供JSON格式的数据接口比如每日订单量、用户增长数、接口错误率。与其每天打开后台看一眼再记到Excel里不如写个脚本把数据抓下来自动生成日报文本或存成CSV顺便对比前一日数据波动。import json import csv import requests from datetime import datetime, timedelta API_URL https://api.example.com/dashboard/stats?date OUTPUT_CSV daily_stats.csv def fetch_date(date_str): resp requests.get(API_URL date_str, timeout10) resp.raise_for_status() return resp.json() def append_to_csv(date_str, data): # 用UTF-8 BOM格式写入方便Excel直接打开不乱码 file_exists Path(OUTPUT_CSV).exists() with open(OUTPUT_CSV, a, newline, encodingutf-8-sig) as f: writer csv.DictWriter(f, fieldnames[日期, 订单量, 新增用户, 错误率]) if not file_exists: writer.writeheader() writer.writerow({ 日期: date_str, 订单量: data.get(order_count, 0), 新增用户: data.get(new_users, 0), 错误率: data.get(error_rate, 0), }) if __name__ __main__: today datetime.now().strftime(%Y-%m-%d) yest (datetime.now() - timedelta(days1)).strftime(%Y-%m-%d) # 抓取前一天和今天数据对比波动 today_data fetch_date(today) yest_data fetch_date(yest) append_to_csv(today, today_data) order_diff today_data.get(order_count, 0) - yest_data.get(order_count, 0) print(f今日订单: {today_data.get(order_count)}较昨日差异: {order_diff:d})这段代码最值得学习的是写入CSV时用了encodingutf-8-sig。直接写UTF-8的CSV文件用Excel打开会乱码因为Excel默认按ANSI读取。加上BOM头之后就不会了。这个细节在自动化办公脚本里非常关键。如果你是想抓外部网站的数据一定注意遵守目标网站的robots.txt规则爬取频率不要太快。我这里的示例用的是内部API接口不存在伦理问题也能清晰展示定时抓取加落地的完整链路。2.10 一键生成新项目目录结构脚本最后一个脚本看起来不起眼实用性却很高。每次新建项目时手动创建一堆目录和文件明明5秒钟能完成的重复劳动却没有任何价值。我把新项目的目录结构预定义好一条命令自动创建顺带生成初始化的README和配置文件。import os from pathlib import Path PROJECT_NAME my_new_project # 预设目录结构按嵌套层级组织 STRUCTURE { src: [main, utils], tests: [test_main, test_utils], docs: [], config: [], scripts: [], } def create_project(name): root Path(name) root.mkdir(exist_okTrue) for folder, subfolders in STRUCTURE.items(): folder_path root / folder folder_path.mkdir(exist_okTrue) for sub in subfolders: (folder_path / sub).mkdir(exist_okTrue) # 生成基础配置文件 (root / README.md).write_text(f# {name}\n\n项目说明\n, encodingutf-8) (root / .gitignore).write_text(__pycache__/\n*.pyc\nvenv/\n, encodingutf-8) (root / requirements.txt).write_text(, encodingutf-8) print(f项目 {name} 创建完成) if __name__ __main__: create_project(PROJECT_NAME)这个脚本不需要任何第三方库修改STRUCTURE字典就能适配你自己的项目习惯。Git仓库里常见的src、tests、docs目录一次生成.gitignore和README.md也顺手写好省得每次新建项目都从空文件夹开始铺路。如果你想更省事可以把这段代码存成.py文件放到系统PATH里然后在任意目录下执行python create_project.py 项目名。由于Python处理路径时用Path对象在不同操作系统上都不会出现/和\不一致的问题。3. 让脚本真正自动跑起来调度与守护脚本写好了但每次手动运行还是不够“解放双手”。自动化脚本的价值在于无人值守关键一步就是配置定时调度。在Windows上最常用的方案是任务计划程序打开“计算机管理”创建基本任务设置触发时间为每天固定时刻操作指向python和你脚本的路径。注意一个细节任务计划程序里“起始于”字段一定要填脚本所在目录否则脚本里的相对路径会找不到文件。在Linux或macOS上用crontab就够了。执行crontab -e加一行0 9 * * * /usr/bin/python3 /home/user/projects/auto_report.py就表示每天上午9点运行一次。用crontab时同样要小心它执行时的当前目录不是脚本所在目录所以脚本内部最好用绝对路径或者基于Path(__file__).parent来拼接路径而不是依赖系统当前目录。3.1 定时任务里最容易踩的坑定时任务跑不起来最常见的原因有三个。第一个是环境变量问题任务计划程序和cron运行时的PATH环境比命令行精简得多你在命令行能用python定时任务里可能找不到这个命令。解决办法是写全python的绝对路径比如C:\Users\你的用户名\AppData\Local\Programs\Python\Python38\python.exe。第二个是工作目录问题这在前面说过。第三个是权限问题如果脚本要访问网络盘或者写系统目录定时任务必须以更高权限运行否则会静默失败。我建议在脚本开头加一行日志输出比如print(f脚本启动时间: {datetime.now()})这样能快速判断定时任务是否真的被触发了。真正排查时我会先把脚本在命令行手动跑一遍确认脚本本身没毛病再去查定时配置基本两步就能定位问题。4. 自动化脚本设计里最值钱的三条原则写了几年自动化脚本我总结出三条原则比任何具体代码都值钱。遵循这三条原则你的脚本才能从“一次性工具”进化为“长期靠谱的机器人”。4.1 幂等性脚本能重跑不添乱幂等性这个词听起来高大上意思就是同一个脚本跑一遍和跑两遍最终结果是一致的不会因为重复执行而搞出乱子。举个反例没有检查文件是否存在的归档脚本第一次跑把日志压缩了第二次跑找不到原文件直接报错。改进方法很简单在执行每个操作前先检查目标状态。文件存在才压缩不存在就跳过Excel合并前先清理输出目录的旧文件重命名时先确认目标文件名未被占用。4.2 异常处理与“无人值守”思维脚本在无人值守时出错你不在现场它也不会主动告诉你。所以一定要加异常捕获和告警机制。简单的做法是把所有可能出错的操作包在try...except里并在异常时调用告警发送邮件或推送到IM机器人。再不济也要把异常堆栈追加到error.log文件里方便事后查。我有个习惯脚本一旦发生异常返回非零退出码比如raise SystemExit(1)这样定时调度工具能识别出脚本失败并在下一次运行时尝试重新执行。4.3 配置与代码分离改需求不熬夜把可变参数抽离到配置文件或命令行参数里是最容易被忽视的设计。比如文件夹路径、收件人列表、API地址、筛选条件这些写死在脚本里虽然在当下能跑但下次需求一改动就要改代码。把配置抽出来放在顶部常量或单独的config.py文件里几秒钟改完不需要去代码里翻找。我的脚本里常把这类参数统一放在文件头部用全大写命名一眼就能分辨哪些是配置、哪些是逻辑。5. 新手最容易踩的坑与排查方法高频踩坑集中在一个地方处理因为这些问题太典型了。我做成一个速查表几乎覆盖了每个新手都会遇到的情况。5.1 环境变量与Python命令找不到Windows安装Python时没勾选“Add Python to PATH”命令行输入python提示不是内部或外部命令。解决办法有两种一是把Python安装目录和Scripts子目录手动加到系统环境变量PATH二是干脆重装并勾选那个选项。macOS/Linux下如果python指向的是Python 2就改用python3命令。在配置定时任务时我强烈建议直接用绝对路径避免这类问题。5.2 路径中包含中文、空格导致失败Windows下C:\Users\张三\Downloads这种路径很多老代码用字符串拼接时容易出问题。Path对象在这方面的健壮性比os.path.join好很多。实在遇到Unicode编码导致的读写错误可以在脚本开头加注释编码声明或者在读写文件时显式指定encodingutf-8。对于包含空格的路径只要不自己手动拼路径字符串、而是用Path对象操作一般都能规避。5.3 编码问题UnicodeDecodeError的应对读取文件报UnicodeDecodeError: gbk codec cant decode byte通常是因为文件是UTF-8编码但Windows默认按GBK打开。解决方式是在open()时明确指定encodingutf-8如果文件来自Windows老系统可能是GBK编码就指定encodinggbk。最麻烦的情况是文件编码混杂那可能需要用chardet自动检测。我在日志脚本里就用了这个方法虽然加了点依赖但省下了人工排查编码的时间。5.4 库安装失败网络、版本、Python版本不匹配pip install超时或者速度慢可以用国内镜像源清华、阿里、豆瓣都有稳定的镜像。pip install pandas -i https://pypi.tuna.tsinghua.edu.cn/simple这个速度比官方源快一个数量级。如果提示Requirement already satisfied但导入还是报错通常是因为你装了包但当前Python环境不对——检查你是不是在虚拟环境之外执行了pip install。还有一种情况是库只支持特定Python版本比如有些老库不支持Python 3.12那就需要把Python降到3.9或3.10再试。关于自动化脚本我最后想说的写脚本这五年我最深的体会是能用脚本解决的事就不要手动重复但也不要为了自动化而自动化。有些场景比如偶尔一次性的文件整理手动做反而更快。判断标准很简单——如果同一个操作你一个月要做三次以上就值得写脚本如果一周要做十次以上那脚本应该放在桌面上配上定时任务做到真正的“免干预”。我在实际使用中还有一个习惯每个脚本都配一个README片段写清楚这个脚本干什么、依赖哪些库、怎么改配置。这样哪怕三个月不碰它再捡起来也能快速上手。这些脚本没有一个是“银弹”但它们精准地解决了我日常工作中最枯燥的重复环节。你不用全部照搬挑上一两个自己用得到的把路径改一改就能直接用。如果你也在哪个怪癖的自动化场景里费过功夫欢迎按同样的思路改良它们。
返回列表