多彩编程 多彩编程MZPH · CODE BLOG
ARTICLE DETAIL

文章详情

深耕前端与后端开发技术的一线实战笔记与踩坑复盘。

Python批量处理Excel和CSV:自动化报表的实战指南

Python批量处理Excel和CSV:自动化报表的实战指南 干过几年数据处理的人谁还没被Excel卡过几次。月初要对账的时候邮箱里躺着几十个各分公司发来的表格格式还不统一有的叫“报表.xlsx”有的是“数据(1).csv”打开一看列名对不上领导还催着下班前出汇总。这时候你大概会想要是有个工具能自动把这些文件全读进来统一整理好再吐出去就好了。这个想法就是今天这篇文章要聊的核心——用Python批量处理Excel和CSV文件。Python在这件事上的优势不是“能处理”而是“批量”和“可复用”。你写一次处理逻辑就能对一个文件夹里几百个文件重复执行下次数据再来一批换条路径跑一遍就行。这个能力对经常跟表格打交道的人很实用——无论是财务月度汇总、运营数据分析、GIS属性表整理还是把临时拉取的CSV转成规范的Excel报送格式都能用同一套思路快速落地。这篇文章我会从环境准备讲起覆盖读取CSV、读写Excel、批量循环处理整个文件夹再到合并多个表格、按条件拆分、跨格式转换这些高频需求最后整理编码、日期、性能这些容易踩坑的点。适合刚接触Python的办公人员也适合想把手头重复工作自动化的数据分析初学者。文章里的代码都能直接复制运行你只需要改一下文件路径。1. 整体设计先把“批量处理”几个字拆清楚1.1 手工操作的真正痛点很多人觉得Excel批量处理无非就是“复制粘贴”但真正上手就知道没那么简单。先说格式不统一有的报表列名是“订单号”有的是“订单编号”还有的是“Order ID”有的日期列存的是“2024-01-15”这种标准格式有的却是“20240115”纯数字更糟的还有“1/15”这种Excel自动转出来的谜之格式。几十个文件堆在一起光对齐表头就能消耗掉大半天。再说合并场景。把几十个文件的数据拼到同一个总表里手工操作除了复制粘贴还得注意别漏行、别重复。粘贴时如果目标表已经有关联公式偶尔还会出现单元格错位的情况。文件一多Excel本身也会卡尤其是单个文件几万行数据时滚动、筛选都迟钝复制粘贴时稍不注意就失去响应。CSV文件就更尴尬了。用Excel直接打开CSV中文经常乱码因为很多CSV是UTF-8编码而老版本Excel默认用ANSI解析如果CSV里某条数据里恰好包含逗号或者换行Excel打开时还会裂成多列看着就头疼。这些情况用Python处理就很简单编码问题可以显式指定带引号的字段也能正确解析。1.2 为什么Python方案能解决问题Python解决这类问题的核心就一条把所有文件当成“同一种结构的数据”用同一套逻辑循环处理。你在第一个文件上验证通过的操作对第100个文件同样生效不会因为文件多了就出错。案例是最直观的。假设手头有20个门店的销售CSV每个文件几千行需要合并成一个总表。手工做至少要半小时还可能出错用Python处理从读取到写出合并结果也就几秒。再比如每个月要把系统导出的CSV转成固定格式的Excel报送表手工做一次要配置导入、调整列宽、改数字格式用Python把这些操作写进脚本后每个月双击一下就完成了。更重要的一点是可复用性。这次写好的脚本下个月数据来了换个路径继续用这个季度想额外加一个汇总Sheet改几行代码就能实现。这比每次手工处理要可靠得多。1.3 技术选型pandas是主力openpyxl是补充做Excel和CSV批量处理Python里主要用三个库pandas、openpyxl、csv。csv是Python自带的轻量模块适合读简单的CSV文件但数据处理能力弱本文不做重点。核心主力是pandas和openpyxl。pandas是这个场景下的标准答案。它把表格数据抽象成DataFrame——你可以理解成一张放在内存里的Excel表有行有列能按条件筛选、按列拼接、按关键字分组。它读取CSV和Excel都非常方便几百行代码的事通常几行就完成。处理大数据量时还支持分块读取不会一下子把内存吃满。openpyxl则专门负责Excel的“精细操作”。pandas能读写Excel的数值和文本但如果你想修改单元格底色、设置边框、调整冻结窗格、写入图片就需要用openpyxl。实际项目中两者通常配合使用pandas负责数据整理openpyxl负责最后的格式美化。库名适用场景优势局限pandas数据分析、合并、筛选、分组、批量转换代码短、性能好、生态成熟对单元格样式控制较弱openpyxl读写Excel格式细节可操作样式、公式、图表大数据量下性能一般csv简单CSV读写无需安装、轻量需要手工处理类型转换2. 环境准备装好Python和两个核心库就能跑2.1 安装Python注意那个“Add to PATH”勾选Python安装本身不难但很多人卡在环境变量上。去Python官网下载对应系统的安装包Windows用户安装时有一个关键的勾选——“Add Python to PATH”这个必须勾上。它把Python的可执行文件路径加进系统环境变量这样你在命令行直接敲python就能启动不用每次去找安装目录。忘了勾也别慌可以手动把Python安装路径添加到系统环境变量里或者卸载重装一次。装好之后打开命令行Windows是CMD或PowerShellmacOS是终端输入python --version能看到类似Python 3.12.x的输出就说明安装成功。Mac和Linux用户有些系统自带Python但版本可能偏老建议直接用官网安装包装最新的稳定版省得后面遇到包不兼容的问题。提示Python 3.8以上版本都能流畅运行本文的代码。如果电脑里同时装了多个Python版本命令会区分成python和python3使用时保持一致就行。2.2 安装pandas和openpyxl一条命令搞定Python装好后安装第三方库统一用pip命令。打开命令行执行pip install pandas openpyxl看到“Successfully installed”就说明装好了。如果网络慢或者安装超时可以切换到国内镜像源清华和阿里云的源速度通常不错pip install pandas openpyxl -i https://pypi.tuna.tsinghua.edu.cn/simple-i参数是指定下载源地址这一步在很多教程里被省略实际上对国内用户来说非常实用。2.3 虚拟环境管理依赖的整洁方案遇到多个项目依赖不同版本的库时虚拟环境能避免“库版本打架”。简单说虚拟环境就是一个独立的Python运行目录你在里面装的库不影响全局环境全局环境里的库也不影响它。创建和使用的命令只有三条python -m venv myenv创建名为myenv的虚拟环境然后激活# Windows myenv\Scripts\activate # macOS / Linux source myenv/bin/activate激活后命令行前面会顶着(myenv)这时候再pip install就只会装进这个环境里。对刚入门的人来说不建虚拟环境其实也够用但如果你同时做着数据分析、爬虫、Web开发等多个方向建议从一开始就养成用虚拟环境的习惯。3. 核心实操从读单个文件到循环处理整个文件夹3.1 读取CSV第一个必学的函数处理的起点永远是“把文件里的数据读进来”。pandas里读取CSV的函数是pd.read_csv()最基本用法是把文件路径传进去import pandas as pd df pd.read_csv(销售数据.csv) print(df.head()) # 查看前5行df.head()能快速确认数据是否成功读取这是我在每个脚本里都会写的第一步调试语句。中文乱码问题在读取CSV时非常常见原因也很简单文件本身用UTF-8编码但Excel默认用GBK或ANSI打开。pandas默认按UTF-8读遇到GBK编码的文件会直接报错或者出现乱码。解决办法是显式指定encoding参数df pd.read_csv(销售数据.csv, encodinggbk)记不住每种文件的编码也不丢人报错时就换一个参数试UTF-8和GBK两个编码几乎覆盖了国内办公场景里的所有CSV文件。如果两个都试过还是乱码可以用chardet库检测文件实际编码但这个场景比较少见。注意有些CSV文件的分隔符不是逗号而是分号、制表符或竖线。pd.read_csv()里可以用sep参数指定比如sep;。打开文件看到数据挤在一列里时首先检查的就是分隔符和编码这两个参数。3.2 读写Excel几个参数决定成败Excle读取用pd.read_excel()df pd.read_excel(订单明细.xlsx, sheet_nameSheet1)sheet_name可以指定工作表名也可以用索引比如sheet_name0代表第一个工作表传一个列表还能一次读多个工作表。写入Excel用df.to_excel()df.to_excel(输出文件.xlsx, indexFalse)这里indexFalse是必须养成的习惯。df的行号默认以整数序列保存如果不加这个参数输出文件里会多出一列无意义的“序号”后面处理数据时会干扰表头对齐。我最初就是忘掉这个参数输出后发现汇总表的第1列全是1、2、3这样的数字还得回头再删。如果你想把多个数据表分别写入同一个Excel文件的不同工作表需要用到pd.ExcelWriterwith pd.ExcelWriter(月度报表.xlsx) as writer: df_sales.to_excel(writer, sheet_name销售) df_stock.to_excel(writer, sheet_name库存)with语句会在代码块结束后自动保存并关闭文件不用手动调用保存方法省心且不容易出错。3.3 批量循环让脚本自己处理整个文件夹批量处理的核心就是“找到所有文件逐个执行同样的操作”。Python里获取文件列表最方便的两个工具是glob和os.listdir。以glob为例假设一个文件夹里放了30个CSV文件import glob import pandas as pd file_list glob.glob(data/*.csv) print(file_list) # 看看匹配到了哪些文件glob返回一个列表里面的每个元素都是匹配到的文件路径。拿到列表之后用一个for循环逐个处理就行。一个最简单的批量转格式脚本长这样import glob import pandas as pd file_list glob.glob(data/*.csv) # 匹配所有CSV文件 for file in file_list: df pd.read_csv(file, encodingutf-8) df[source_file] file # 加一列标记数据来自哪个文件 df.to_excel(file.replace(.csv, .xlsx), indexFalse) print(f{file} 处理完成共 {len(df)} 行)这个脚本做的事情有读取CSV、给每一行打上来源标记、转成Excel文件、打印处理日志。运行一遍一个文件夹里所有CSV文件都转成了Excel文件名不变只替换了扩展名。这个模式可以迁移到各种操作上——筛选特定条件、新增计算列、删除重复值都可以塞进这个循环体里。处理日志里的f{file} 处理完成共 {len(df)} 行是f-string语法用来在字符串里嵌入变量值。它除了让你在执行时能实时看到进度跑完后还能核对每个文件是否被正确读取避免“静默失败”。4. 进阶玩法合并、拆分、格式转换一次讲透4.1 合并多个表格pd.concat一行解决把几十个结构相同或相似的表格合并成一张总表是办公场景里最高频的需求。pandas的做法是先逐个读取再统一合并。import glob import pandas as pd file_list glob.glob(data/*.xlsx) df_list [] for file in file_list: df pd.read_excel(file) df_list.append(df) df_all pd.concat(df_list, ignore_indexTrue) df_all.to_excel(合并总表.xlsx, indexFalse)pd.concat沿着行的方向把多个DataFrame堆叠起来ignore_indexTrue表示重新生成连续的行号否则合并后的表行号会保留各文件的原始索引看起来是乱的。这里有一个常见问题如果各文件的列顺序不一致合并后会不会错位答案是不会。pd.concat默认按列名对齐而不是按位置对齐。也就是说A文件列名叫“金额”B文件列名叫“金额”会正确对齐到同一列如果某列只有一个文件有另一个文件没有缺失部分会自动填成NaN空值。这比手工粘贴安全得多。4.2 按条件拆分groupby to_excel组合批量操作不只是“合并”把一个大表拆成多个小表也是常见的需求。比如一张全国门店的销售总表希望按城市拆分成单独的文件每个城市一个Excel。用groupby就能实现import pandas as pd df pd.read_excel(全国销售总表.xlsx) for city, group in df.groupby(城市): group.to_excel(f拆分结果/{city}.xlsx, indexFalse) print(f{city} 已导出共 {len(group)} 行)先按“城市”列分组得到每个组对应的数据子集再分别导出。第一次跑之前记得先建好拆分结果这个文件夹不然会报文件路径不存在的错误。运行结束后同样可以用文件夹里生成的文件数量与分组数核对确保每次导出都成功。除了导出多个文件也可以把一个Excel文件的多个Sheet拆出来做进一步处理。pd.read_excel()的sheet_nameNone可以一次读取所有工作表all_sheets pd.read_excel(多表.xlsx, sheet_nameNone) for sheet_name, df in all_sheets.items(): print(sheet_name, len(df))这时all_sheets是一个字典键是工作表名值是对应的DataFrame拿到之后想怎么处理都方便。4.3 Excel和CSV互转注意格式损失Excel转CSV是导出数据给其他系统用的高频操作反过来把CSV变成Excel做后续展示也很常见。核心代码在上面已经出现过但要提醒一条细节CSV只保存数据和逗号分隔符不保存Excel里的单元格格式、列宽、颜色、公式。如果你原表里有用公式计算的列转成CSV后再读回来数值变成了静态结果公式本身丢了。这一点在转换前要想清楚。反过来CSV转Excel也会遇到问题。CSV里经常有超长数字串比如订单编号、身份证号用Excel直接打开会自动转成科学计数法看着是1.24015E17这种完全没法用。用pandas读取时可以先把这一列转成字符串类型再写入Exceldf pd.read_csv(订单.csv, dtype{订单编号: str}) df.to_excel(订单.xlsx, indexFalse)dtype参数指定读入时的数据类型把订单编号按字符串读取就等于告诉pandas“别把它当数字处理”。或者读取后再转换也行df[订单编号] df[订单编号].astype(str)这一步看着简单但能避免很多后续对账时的数据错乱问题。4.4 跨场景实用案例GIS、量化、文档表格和AI流程批量处理表格的应用场景远不止财务汇总和报表整理实际工作里还有几个高频场景值得单独说。GIS方向很多人用ArcGIS做制图经常需要把Excel里的点坐标数据导入GIS生成要素文件。Excel能转CSV但ArcGIS读CSV时对表头、字段类型很敏感通常建议把表头改成英文字段名经纬度单独成列数值字段不要带千分位分隔符。这一步交给Python做是轻车熟路读取原始Excel、重命名列、清洗数值、导出成规范的CSV文件再进ArcGIS的“添加XY数据”工具比手工在Excel里改一个小时靠谱得多。量化交易方向行情数据常常是CSV格式一天一个文件或者一个月一个文件做回测前需要把历史数据合并、清洗、统一时间戳。pandas的pd.to_datetime()可以统一日期格式df.sort_values()按时间排序df.drop_duplicates()去重都是量化数据预处理里每天要用的操作。文档方向Markdown里偶尔需要转表格到Excel或者从Excel反向生成Markdown表格。pandas读出Excel数据后用df.to_markdown()可以一步生成Markdown格式的表格复制到文档就能用反过来把Markdown表格先转成CSV再用pandas读进来也方便。AI知识库和本地文档处理方向也有用武之地。像RAGFlow这类知识库工具支持批量导入文档但文档里的表格往往需要先转成规范格式才能被正确解析。这时候用Python把Excel、CSV统一清洗成UTF-8编码的标准表格文件再导入知识库能有效提高后续检索和问答的准确率。我自己在实际操作中就对一批杂乱的CSV做过去除空行、统一列名、转成标准分隔符的预处理后续导入流程顺畅了很多。5. 避坑手册编码、日期、大数据量是重灾区5.1 编码问题UTF-8和GBK的纠葛CSV读取中最常见的报错就是UnicodeDecodeError打开控制台看到这个红字十有八九是编码参数不对。解决方案很简单先试encodingutf-8报错就换encodinggbk。如果你自己写CSV文件建议全程用utf-8df.to_csv(输出.csv, indexFalse, encodingutf-8-sig)注意这里我用了utf-8-sig而不是utf-8。utf-8-sig会在文件开头写入一个字节序标记BOMExcel识别这个标记后能正确按UTF-8解析不会乱码。如果用纯utf-8Excel打开还是乱码这是很多人在本地CSV转Excel后遇到的“薛定谔的乱码”问题。一个小参数的差别决定文件能不能被Excel正常打开这事我踩过好几次了。5.2 日期数据Excel序列号与字符串的纠缠日期列是另一个让人头大的部分。Excel内部把日期存成从1900年1月1日起的序列号比如45292代表2024年1月15日但CSV里导出的日期往往是“2024-01-15”这样的字符串。pandas读取时日期列默认会是字符串类型object如果直接拿去排序或过滤得到的结果完全不对因为字符串比较的“2024-11”会排在“2024-9”前面。解决办法是读取后统一转成真正的日期类型df[下单日期] pd.to_datetime(df[下单日期])pd.to_datetime()能自动识别多种常见日期格式并统一成标准格式。转换之后做筛选、排序、按月汇总语义就对了。如果源文件是Excel可以在读取时用parse_dates参数指定需要转换的列一步到位df pd.read_excel(订单.xlsx, parse_dates[下单日期])处理完日期如果要按月份统计可以把日期列转成月份标记df[月份] df[下单日期].dt.to_period(M)然后再用groupby(月份)汇总比手工在Excel里拖数据透视表灵活得多。5.3 性能问题循环不是万能的批量处理的文件一多、数据量一大运行时长的差距就很明显。几十个几万行的文件用pandas处理基本毫无压力但如果你一个文件就上百万行而且循环体里逐行做操作那脚本跑起来就会越来越慢。逐行操作是新人最常犯的性能错误# 这个写法不推荐太慢了 for i in range(len(df)): df.loc[i, 新列] df.loc[i, 旧列] * 2pandas里“逐行修改”的效率远低于“整列计算”# 这个写法好得多 df[新列] df[旧列] * 2整列计算在底层由C语言实现性能高两个数量级。类似地筛选条件数据用布尔索引不要用循环遍历判断。5.4 大文件分块chunksize处理内存溢出的招单文件特别大时几GB的CSV很常见pd.read_csv()一次性读入可能直接把内存吃满轻则卡死重则进程被杀。这时候用chunksize参数分批读取chunk_iter pd.read_csv(超大.csv, chunksize100000) for chunk in chunk_iter: # 对每个chunk处理 print(len(chunk))chunksize100000表示每次只读取10万行处理完再读下一批。如果你的任务是统计这类大文件的总行数、总和、平均值可以边读边累加。这个思路和“一次不要吃太多分几口吃”是一样的适合超大文件的统计和过滤场景。5.5 写出路径与文件覆盖脚本跑完找不到输出文件的经历很多人都遇到过。原因往往是输出路径没有写完整或者文件保存到了脚本运行时的当前目录而这个目录和你打开文件夹的位置不一样。建议在脚本开头就把输入输出路径定义清楚input_dir D:/工作/原始数据/ output_dir D:/工作/处理结果/运行脚本之前确认输出文件夹已经创建好。也可以在脚本里自动创建文件夹import os os.makedirs(output_dir, exist_okTrue)exist_okTrue表示文件夹已存在时不报错。这个参数是“幂等”的思路——同一个脚本跑第二次不会因为路径已存在而中断批量处理的脚本更应该做到这一点。5.6 和Excel插件的联动问题最后补充一个和Excel自身有关的坑。有些电脑上Excel的“加载项”可能提示被禁用比如Power Query、分析工具库等这类情况多数是因为组件被关闭或版本限制通常不影响Python直接读写文件。但如果你的目标是用Python生成一个带宏或带复杂格式的Excel文件需要注意openpyxl保持的格式有限。遇到和Excel本身的交互问题比如CtrlV粘贴失效这更多是Excel软件设置层面的问题和Python脚本无关排查时不要混在一起。6. 最后的实战总结从写脚本到负责任地交付前面讲了这么多最后落回到实际工作的一个完整案例上。假设你是运营每周要出一份销售周报数据源是系统导出的10个CSV你需要把CSV按门店合并去掉重复订单只保留交易金额大于0的记录加一列“周内日期序号”方便透视最后输出一个格式统一的Excel。完整脚本大概是这样的import glob import pandas as pd # 1. 读取所有CSV文件 file_list glob.glob(data/*.csv) df_list [] for file in file_list: df pd.read_csv(file, encodingutf-8-sig) df_list.append(df) # 2. 合并成一张表 df pd.concat(df_list, ignore_indexTrue) # 3. 去重、过滤 df df.drop_duplicates(subset订单号) df df[df[交易金额] 0] # 4. 添加周内日期序号 df[下单日期] pd.to_datetime(df[下单日期]) df[周内序号] df[下单日期].dt.dayofweek 1 # 5. 输出Excel df.to_excel(销售周报.xlsx, indexFalse) print(f处理完成共导出 {len(df)} 条有效记录)这段代码把一个需要人工操作半小时以上的流程压缩成了电脑自动执行的几秒钟。整个过程里的关键点读取时指定编码合并时忽略索引去重时明确依据列过滤时保留有效数据最后输出时关掉索引列。我在实际使用中最深的体会是脚本本身不难难的是处理那些“脏数据”。文件命名不规律、列名大小写不一致、日期格式变来变去、数字列里混着“—”“待定”之类的文本这些才是批量处理里真正消耗精力的地方。所以每次跑完脚本一定要抽查几行结果确认数据没有系统性偏差再决定是否用于汇报或入库。如果你刚开始学建议先从一个小场景练手找十几张同类的CSV写一个只做“读取、合并、输出”的三行代码脚本跑通后再逐渐加入筛选、去重、清洗逻辑。这个过程中不断积累处理异常的经验以后遇到再乱的表格打开Python心里都不慌。
返回列表