ARTICLE DETAIL

资讯详情

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

10个Python实用自动化脚本:合并Excel、抓取数据、监控日志

10个Python实用自动化脚本:合并Excel、抓取数据、监控日志 每天打开电脑总有一堆重复操作等着你把十几个Excel表合成一张、把上千张照片压缩一遍、盯着网页等某个数据更新、手动从数据库拉报表再发群里。这些事看着不大但日积月累时间的损耗相当惊人。我用Python写了不少自动化脚本今天挑出10个最高频、最实用的按“处理文件、抓取数据、解放运维”三类场景整理出来。这篇文章不仅给你们代码更会把每个脚本的设计思路、关键参数怎么选、踩过什么坑都讲清楚。适合刚学Python的入门用户也适合每天被机械操作折磨的办公室人群你不需要成为编程高手装好Python、复制代码、稍微改两行路径就能用。1. 自动化脚本的设计思路先搞清楚值不值得“自动化”很多人一上来就问“我要学哪些脚本”但我更喜欢先聊判断标准。不是所有操作都值得写脚本高效自动化的前提是三个条件同时满足操作足够高频、流程完全规则化、失败时能快速定位。以“每周合并销售报表”为例如果只是偶尔做一次手动复制粘贴可能只要10分钟写脚本反而花一小时那就不划算。但如果是每天都要做、涉及几十个文件、表头还有变化脚本的价值就完全体现出来了。判断准则是“重复三次以上的手动操作就值得花时间写脚本”。选Python而不是其他语言图的是它的生态。文件处理有os和pathlib表格有pandas和openpyxl抓网页有requests和BeautifulSoup监控有logging和smtplib几乎每个场景都有成熟的第三方库。这意味着你不用从零造轮子大部分脚本60%以上的代码都是调用现成工具。这套脚本整理下来我习惯按“输入、处理、输出”三段式拆解。输入环节搞清楚数据从哪里来是本地文件、网络接口还是数据库处理环节是核心要明确规则怎么写输出环节决定最终产物是另存为一个文件、推送到某个平台还是只打印日志。把这三段理清脚本结构自然就通了。提示脚本不是越短越好也不是功能越多越好优先级永远是“能跑、稳定、出错时看得明白”。代码写得再炫隔两个月你自己都看不懂就等于报废了。1.1 这10个脚本的场景分类先给你们一张总览表后面逐个拆解时心里有个底。场景类别脚本名称核心库解决什么问题文件处理多表数据合并pandas, glob合并几十个Excel文件文件处理文件名批量规范化os, re统一格式、去重、补日期文件处理临时文件自动清理pathlib, time按时间规则删除旧文件文件处理图片批量压缩Pillow批量缩小图片体积办公文档PDF关键页提取pdfplumber从一堆PDF里提取指定页办公文档Word模板批量生成python-docx批量生成合同/通知数据抓取网页信息定时推送requests, time盯数据变化并推送通知数据抓取图片OCR文字识别pytesseract批量提取图片文字运维监控日志异常自动告警logging, smtplib扫描日志并邮件告警运维监控数据库自动拉表pyodbc, pandas定时拉取报表并归档2. 文件与办公自动化把重复劳动压缩到几秒先讲最贴近日常办公的6个脚本。这些脚本的共同特点是把你要花半小时以上手工完成的活儿压缩到几秒钟执行完。2.1 多表数据合并不再逐个“复制、粘贴”这是使用率最高的脚本没有之一。月末财务对账、汇总各业务线数据、合并全班成绩单……凡是遇到“几十个Excel的结构相同只需要拼接”的活用它就对了。import pandas as pd import glob files glob.glob(rD:\data\*.xlsx) all_data [] for f in files: df pd.read_excel(f, sheet_name0) all_data.append(df) merged pd.concat(all_data, ignore_indexTrue) merged.to_excel(rD:\data\合并结果.xlsx, indexFalse) print(f已合并 {len(files)} 个文件共 {len(merged)} 行数据)核心原理就四条glob按通配符扫描目录拿到全部文件路径pd.read_excel逐个读取pd.concat按行拼接最后to_excel输出。看起来简单但有几个细节要特别注意。Sheet名不要写死用sheet_name0读第一个Sheet因为业务部门交来的文件往往改名了。表头必须完全一致如果有的文件多了一列少了一列concat后会出现大量空值和错位建议合并前先做个校验set(df.columns) set(template.columns)不一致时打印文件路径并跳过。数据类型也是常见坑。同一个“工号”列在A表里是文本“00123”在B表里被Excel转成了数字123拼完后全乱了。解决办法是在read_excel时加上dtypestr参数强制所有列读成文本再按需转换。实操心得如果分表列名有小差异建议把pd.concat换成merged pd.concat(all_data, joinouter)宁可保留多余列也不要丢数据。2.2 文件名批量规范化正则表达式拯救强迫症从网上下载的资料、相机导出的照片文件名经常是“IMG_2389 (1).jpg”“文档(最终版)(1).docx”这种。手动改到心累用脚本十几秒就全搞定了。import os, re folder rD:\downloads for name in os.listdir(folder): path os.path.join(folder, name) if not os.path.isfile(path): continue new_name re.sub(r\s*\(\d\), , name) new_name re.sub(r下载|copy|副本, , new_name) new_name re.sub(r[【】\[\]], , new_name) if new_name ! name: os.rename(path, os.path.join(folder, new_name)) print(f{name} - {new_name})这套脚本的核心就是正则替换。\s*\(\d\)匹配空格加括号加数字也就是“(1)”“(2)”这类浏览器下载自动加的后缀下载|copy|副本是常见冗余词[【】\[\]]清理全角半角括号。每条规则都对应一类真实命名残留你们可以按自己场景不断增加规则比如加re.sub(r[年月日], -, new_name)把中文日期改成横线连接。重名问题要提前想好。如果改完的新名字已经存在os.rename会直接覆盖原文件。我一般在改名之前建一个字典记录已有文件名重名时自动在尾部加_new。注意路径里有中文时Windows下偶尔会触发编码问题。在Python的字符串前面加r声明原始字符串可以避免反斜杠转义坑。2.3 临时文件自动清理定时任务里的家庭大扫除不管是服务器还是个人电脑时间久了downloads文件夹总会堆积几百个没用的临时安装包、旧日志文件。这个脚本配合系统定时任务可以帮你每周自动清理一次。from pathlib import Path import time folder Path(rD:\downloads) cutoff time.time() - 7 * 24 * 3600 # 7天前的时间戳 for f in folder.iterdir(): if f.is_file() and f.suffix in [.tmp, .log, .zip, .exe]: if f.stat().st_mtime cutoff: f.unlink() print(f已删除 {f.name} ({time.strftime(%Y-%m-%d %H:%M, time.localtime(f.stat().st_mtime))}))判断逻辑很简单先限定后缀白名单再比较文件修改时间超过7天就删。这里有一个变量值得说清楚7 * 24 * 3600计算的是7天总秒数st_mtime拿到的也是时间戳秒数两者单位一致才能直接比较大小。如果觉得直接删除风险太大可以启动“观察模式”——脚本只打印哪些文件会被删不实际执行删除操作。把f.unlink()注释掉运行一周看看效果确认没问题再恢复这是我处理任何“删除类”脚本的固定操作。2.4 PDF关键页提取从几十页报告中抽你要的那几页做方案的同学经常要“把某某报告的3-5页和12页发给客户”用工具手动拆页太麻烦用脚本来得更干净。import pdfplumber pdf_path rD:\报告\产品说明.pdf out_path rD:\报告\关键页.pdf pages [2, 3, 4, 11] # 第3、4、5、12页索引从0开始 with pdfplumber.open(pdf_path) as pdf: writer [] for i in pages: if i len(pdf.pages): writer.append(pdf.pages[i]) with pdfplumber.open(out_path) if False else __import__(io).BytesIO() as buf: # 合并页需要借助PyPDF2或pdfrw这里用个更轻的思路 pass先说明上面这段代码有个“未完成”的感觉我自己实际用的是更简洁的方案直接用PyPDF2的PdfWriter逐页读取再写入新文件代码反而更清晰。from PyPDF2 import PdfReader, PdfWriter reader PdfReader(rD:\报告\产品说明.pdf) writer PdfWriter() for i in [2, 3, 4, 11]: writer.add_page(reader.pages[i]) with open(rD:\报告\关键页.pdf, wb) as f: writer.write(f)这里唯一的坑是索引错位。PDF第1页对应索引0凡是有人告诉你要“第X页”都先自己减1验证一遍。我甚至会额外跑一段打印总页数的代码len(reader.pages)确认页数没超出范围不然直接报错。2.5 Word模板批量生成合同、通知全靠它“给200个员工发录用通知书内容大同小异就姓名和岗位不同”这是Word批量生成脚本最典型的使用场景。先做一个Word文档作为模板把需要变化的字段用{{姓名}}、{{岗位}}这种占位符标出来再用脚本批量替换生成新文件。from docx import Document source_file rD:\模板\通知书模板.docx employees [{name: 张三, position: 产品经理}, {name: 李四, position: 后端工程师}] for emp in employees: doc Document(source_file) for para in doc.paragraphs: para.text para.text.replace({{姓名}}, emp[name]) para.text para.text.replace({{岗位}}, emp[position]) doc.save(rfD:\输出\通知书_{emp[name]}.docx)替换的原理是遍历段落后检查文本内容用str.replace做全局替换。但这个方案有个局限如果你的字段在Word表格里不在普通段落里只遍历doc.paragraphs是找不到了。这时候要同时遍历doc.tables里的每个单元格cell.text同样执行一遍replace再写回。更复杂的动态表格和图片填充就要用doc.add_table和add_picture来生成网上例子很多我们按需扩展即可。注意模板里不要用“文本框”承载占位符python-docx默认读不到文本框里的内容。如果模板是别人做的先检查一下否则生成的文件里会出现“{{姓名}}”原样输出。2.6 图片批量压缩一张图几千字的“瘦身”术写公众号、传素材库时最烦图片太大。用Pillow库可以批量把图片从5MB压到500KB宽高按比例缩小画质肉眼几乎无损失。from PIL import Image from pathlib import Path folder Path(rD:\photos) out_folder folder / compressed out_folder.mkdir(exist_okTrue) for f in folder.iterdir(): if f.suffix.lower() in [.jpg, .jpeg, .png]: img Image.open(f) img.thumbnail((2000, 2000)) # 等比缩到长边不超过2000 img.save(out_folder / f.name, quality85, optimizeTrue) print(f{f.name}: {f.stat().st_size // 1024}KB - {(out_folder / f.name).stat().st_size // 1024}KB)核心就两行thumbnail等比缩放save里的quality85控制压缩率。质量参数建议设置在80-90之间低于75能明显看到文字边缘发虚高于90又压不出体积差。还要注意thumbnail和resize的区别是thumbnail保持原图比例只会缩小不会拉伸resize则可能变形需要自己算宽高比。处理批量图片时用thumbnail更安全。3. 数据抓取与运维监控让“盯数据”这件事自动化这类脚本的价值不在“写一次用一次”而在于配好定时任务后它能在你睡觉时替你盯数据、替你发告警做到真正的“无人值守”。3.1 网页关键信息定时推送盯着价格和榜单变动想监控某个商品价格变化、某篇文章阅读量更新写一个“轮询判断”脚本发现变化就推送通知到手机这是爬虫类里面最实用的一种。import requests, time from bs4 import BeautifulSoup target_url https://example.com/data push_url https://push-api.example.com/send # 换成你的通知webhook last_value None while True: resp requests.get(target_url, timeout10, headers{User-Agent: Mozilla/5.0}) soup BeautifulSoup(resp.text, html.parser) now_value soup.select_one(.price).text.strip() if last_value is not None and now_value ! last_value: requests.post(push_url, json{msg: f价格变化: {now_value}}) print(f[{time.strftime(%H:%M:%S)}] 变化: {last_value} - {now_value}) last_value now_value time.sleep(300) # 5分钟查一次核心思路是个“状态机”last_value记录上一次的值循环里每次重新抓取只有发生变化才推送避免频繁打扰。这是“事件驱动”的经典思路比固定每分钟推送实用得多。请求头里的User-Agent是必带的很多网站反爬第一道关就是识别UA。timeout要显式设置否则个别请求卡住时整个脚本会僵死在那里。实操心得监控类脚本最忌讳的是“崩了都不知道”。把脚本改成“出现异常立即推送告警”比如except Exception as e: requests.post(push_url, json{msg: f监控脚本报错: {e}})这样脚本死了你反而第一时间能发现。关于推送渠道最省事的是用“Server酱”或者Telegram Bot的webhook把告警内容POST到对应接口。不想依赖第三方的话也可以用smtplib发邮件到手机邮箱邮件客户端会主动推送通知。这个后面第3.4节再展开。3.2 图片OCR文字识别两百张打卡截图一次搞定业务上有“把截图里的文字提取出来填表”的需求手动一张张打字非常浪费时间。OCR脚本把图片交给识别引擎自动输出文本再写入Excel。from PIL import Image import pytesseract import pandas as pd file_list [rD:\打卡记录\01.png, rD:\打卡记录\02.png] results [] for f in file_list: text pytesseract.image_to_string(Image.open(f), langchi_simeng) results.append({file: f, text: text}) df pd.DataFrame(results) df.to_excel(rD:\打卡记录\识别结果.xlsx, indexFalse)我实际用过tesseract和rapidocr两个引擎后者对中文识别率明显更好但CPU占用感人处理大量图片时风扇狂转。如果图片量大建议批量处理前先压缩尺寸识别的速度能差好几倍。识别质量的坑在于图片清晰度。手机截图没问题但拍照的文档一定要先做“灰度化二值化”预处理Image.open(f).convert(L)可以大幅提高对比度减少噪点。我踩过这个坑最初直接用彩色图识别错误率高得离谱转成灰度后准确率立刻上来了。注意识别出来的文字通常包含大量换行和杂项符号不要直接进Excel。用re.sub(r\s, , text)把空白压缩成单个空格再按业务规则用split拆列。3.3 日志监控与异常告警半夜“盯梢”不用自己醒服务器日志每天生成几百MB但真正需要关心的只有ERROR和Timeout。这个脚本定时扫描日志文件把匹配到的异常行提取出来汇总后发邮件。import smtplib, re, time from email.mime.text import MIMEText from pathlib import Path log_path Path(r/var/log/app.log) errors [] for line in log_path.open(errorsignore): if re.search(rERROR|Timeout|Connection refused, line): errors.append(line.strip()) if len(errors) 10: # 超过阈值才告警避免鸡毛蒜皮 msg MIMEText(\n.join(errors[-20:]), plain, utf-8) msg[Subject] f[应用告警] {len(errors)} 条异常日志 msg[From] alertexample.com msg[To] opsexample.com smtp smtplib.SMTP_SSL(smtp.example.com, 465) smtp.login(alertexample.com, password) smtp.send_message(msg) smtp.quit()核心逻辑是“正则匹配 阈值熔断”errors[-20:]取最近20条防止日志太多后邮件爆量。为什么要设阈值因为有些业务日志的ERROR是正常状态的一部分比如偶尔的网络抖动全部推送给只会让告警变成噪音最后真正出问题时反而没人看邮件。smtplib.SMTP_SSL走的是465端口SSL加密发送前需要在邮箱后台开启“SMTP服务”并获取授权码。这里提醒一句不要往代码里写明文密码。把密码放到环境变量os.environ[MAIL_PASS]里或者放到单独配置文件中并设置只有本人可读的权限避免代码被误传后泄露。3.4 数据库自动拉表再也不用在“数据后台”手动导出公司系统如果开了数据库只读账号你就可以用脚本定时把业务表拉下来归档或做二次分析。这也是“AI自动化”话题里最实在的一类应用。import pyodbc, pandas as pd conn_str rDRIVER{ODBC Driver 17 for SQL Server};SERVER10.0.0.5;DATABASEreport;UIDreader;PWD你的密码 conn pyodbc.connect(conn_str) query SELECT date, zone_id, sales_amount FROM daily_sales WHERE date DATEADD(day, -1, GETDATE()) df pd.read_sql(query, conn) df.to_excel(rfD:\data\daily_sales_{pd.Timestamp.now():%Y%m%d}.xlsx, indexFalse) conn.close()数据库连接串的格式看着唬人但其实就是“驱动 地址 实例 账号密码”五件套。需要先安装对应的ODBC驱动很多系统报错“找不到驱动”都是因为缺了ODBC Driver 17 for SQL Server或MySQL ODBC 8.0去微软或MySQL官网下载安装就行。脚本里DATEADD(day, -1, GETDATE())是SQL Server语法意思是取昨天数据。如果公司库是MySQL要改成WHERE date DATE_SUB(CURDATE(), INTERVAL 1 DAY)。很多人的连接查询没有问题却卡在SQL方言上这部分一定要先确认库类型。注意数据库账号权限务必要申请“只读”权限。自动化脚本只在需要查数据、写文件不需要对生产库做任何写操作。如果你用的账号能写万一代码里多执行了一条DELETE后果不堪设想。3.5 定时任务调度Windows和Linux怎么“到点执行”脚本写好了不可能每次都手动双击运行。定时任务调度是自动化脚本从“玩具”变成“生产力工具”的关键一步。Windows上可以用“任务计划程序”创建基本任务设置触发器为“每天/每周”操作选择“启动程序”程序填python.exe的路径参数填你脚本的完整路径。注意python.exe最好用绝对路径比如C:\Python312\python.exe因为任务计划程序的环境变量和你的命令窗口不一样直接填python可能找不到。Linux或者macOS上更简单用的是crontab# 每天凌晨2点执行数据拉表脚本 0 2 * * * /usr/bin/python3 /home/ops/scripts/auto_report.py /home/ops/logs/auto_report.log 21cron的五段格式分别是“分钟、小时、日、月、星期”0 2 * * *表示每天凌晨2点0分。最后的 log 21把脚本的标准输出和错误都追加写入日志文件这是调试定时任务最关键的技巧——脚本悄悄失败的时候日志是唯一能告诉你“为什么失败”的线索。实操心得定时任务最坑的是“环境变量不一致”。手动能跑、定时跑不了90%都是因为PATH里没找到Python路径或第三方库路径。解决办法是脚本开头加两行import sys和sys.path调整或者干脆用venv里Python的绝对路径来跑。4. 环境准备与脚本维护把这些自动化脚本装进“保险箱”脚本不是写完就结束了。保存好依赖、设计好异常处理才能让代码在半年后依然“能跑”。4.1 虚拟环境与依赖导出我用venv为每个脚本组单独建环境不要一股脑把pandas、Pillow全堆在全局环境。虚拟环境的好处是各项目之间依赖隔离比如脚本A需要pandas1.5.3脚本B需要pandas2.2.1互不干扰。python -m venv venv venv\Scripts\activate # Windows # source venv/bin/activate # Linux/macOS pip install pandas pillow requests pdfplumber python-docx pytesseract pyodbc pip freeze requirements.txtpip freeze requirements.txt会把当前环境所有库名和版本号导出。以后换新机器执行pip install -r requirements.txt就能完整还原环境。别贪心一次性装一堆库跑哪个脚本缺哪个再补哪个依赖越少越好维护。4.2 异常处理和日志记录别让脚本“静默死亡”写脚本时最怕的就是“跑着跑着没反应了也不报错”。所以每个脚本最好都套一个顶层异常捕获把错误信息记录到专门的日志文件里。import logging logging.basicConfig( filenamerD:\scripts\auto_report.log, levellogging.INFO, format%(asctime)s [%(levelname)s] %(message)s ) try: # 主逻辑 logging.info(脚本开始执行) except Exception as e: logging.error(f脚本崩溃: {e}, exc_infoTrue) raiseexc_infoTrue会把完整堆栈信息写进日志定位问题时根本不用再翻代码猜“错在第几行”。很多同学报错处理只写print(e)打印完控制台一关就什么都没留住不好定位。日志级别建议日常用INFO出错用ERROR。调试阶段可以临时切到DEBUG看更多细节正式跑定时任务时再调回INFO避免日志文件膨胀。我个人的习惯是每个脚本至少打印首行和尾行日志比如“开始执行”和“执行完成共处理12个文件”。定时任务跑没跑、跑完没有一眼就能从日志看出来。5. 常见问题与排查技巧实录这里整理了我实际用这些脚本时最常遇到的几个问题按“症状—原因—解决”的方式列出来方便你们对照排查。症状常见原因解决办法读取Excel报错后缀是.xls但实际是.csv用pd.read_csv读或先另存为xlsx中文路径报错Windows控制台编码问题路径前加r文件开头加# -*- coding: utf-8 -*-pandas没找到数据读到了Sheet名但结构变了改成sheet_nameNone读全部Sheet再按需筛选OCR识别中文乱码缺少中文语言包pytesseract.get_languages()确认chi_sim在不在定时任务不触发触发器配置错误或程序路径不对核对任务计划程序的“起始于”和python绝对路径爬虫被反爬请求头太“素”添加User-Agent、Referer、Cookie控制访问频率脚本运行卡住网络请求无超时所有requests.get必须加timeout推荐5-10秒数据库连接失败ODBC驱动未安装到官网装对应驱动连接串的驱动名要和已装版本一致Excel生成后打开报错文件正被程序占用先关闭Excel文件再运行脚本或改输出文件名图片风火轮狂转大尺寸图片未压缩先在脚本里做thumbnail((2000, 2000))缩小再处理这里单独说说排查的通用思路所有自动化脚本出问题都可以按这个顺序来先看日志文件有没有报错堆栈再手动用命令行跑一次脚本看是否复现定位到具体一行后用最小测试数据验证。不要上来就改代码很多时候是自己的输入数据变了不是代码逻辑错了。另一个高频坑是“脚本在电脑A能跑在电脑B报错”。八成是环境不一致先对比pip list输出把缺失的库补上。python版本差异也会作妖比如pathlib在Python 3.4以上才有如果公司服务器上还是Python 2很多新语法直接不能运行。写脚本前第一件事python --version确认版本第二个是不同机器之间不要依赖绝对路径尽量用Path(__file__).parent定位脚本目录这样脚本拷到哪都能跑。如果你用Anaconda管理多个Python环境还要注意“环境串味”问题。命令行里通过conda activate切换环境否则装库可能装到base环境最后脚本运行时根本读取不到这些第三方包。这属于最容易把头挠秃的一类问题却也是最容易排查的一类——看一行pip show就能确认。再分享一个小技巧给脚本加个“干跑模式”。通过命令行参数--dry-run控制默认只打印“将要做什么”而不实际执行。这样不管新部署的脚本还是大改后的脚本都能先安全试运行几天确认逻辑无误后再放开真实操作权限。这个习惯帮我躲过好几次“批量误删文件名”的麻烦。我在实际使用中的体会是自动化脚本的核心价值不在于省下的那几分钟而在于它把人的注意力从重复劳动里解放出来让你能去做真正需要判断和创造的事情。当每个脚本都用日志、异常处理和干跑模式武装好之后它们的维护成本会变得非常低你会越来越愿意把更多琐事交给它们。
返回列表