ARTICLE DETAIL

资讯详情

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

Python自动化Excel数据处理:从Pandas读写到Openpyxl报表生成

Python自动化Excel数据处理:从Pandas读写到Openpyxl报表生成 1. 项目概述为什么Python处理Excel是必备技能如果你在工作中需要经常和数据打交道无论是市场分析、财务对账、库存管理还是自动化报表那么“用Python读写Excel文件”这个技能几乎可以立刻将你从繁琐的重复劳动中解放出来。我见过太多同事每天花几个小时在Excel里手动复制粘贴、调整格式、核对数据不仅效率低下还容易出错。而Python凭借其强大的数据处理库可以让你用几行代码就自动化完成这些任务。简单来说Python读写Excel的核心价值在于自动化和批量化。想象一下你需要合并10个部门提交的、格式各异的Excel报表或者需要从几百个文件中提取特定数据并生成汇总图表。手动操作不仅耗时一旦源数据更新所有工作都得重来。用Python写一个脚本这些问题就变成了“一键运行”。无论是openpyxl、pandas还是xlrd/xlwt这些库都提供了丰富的接口让你能像搭积木一样构建出复杂的数据处理流程。这篇文章我会从一个多年数据工程师的角度带你彻底掌握Python操作Excel的方方面面。我们不只讲“怎么用”更会深入“为什么这么用”以及在实际项目中那些容易踩坑的细节。无论你是刚入门Python还是已经写过一些脚本但总遇到奇怪报错相信都能在这里找到答案。2. 核心库选型根据你的场景选择趁手的工具面对“Python读写Excel”新手最容易犯的错就是随便抓一个库就开始用结果发现要么功能不全要么性能瓶颈要么文件格式不支持。市面上主流的库各有侧重选对了工具事半功倍。2.1 主流库横向对比与适用场景首先我们得明确一个关键区别Excel文件有两种主要格式——传统的.xlsExcel 97-2003和现代的.xlsxExcel 2007及以上。.xlsx本质是一个ZIP压缩包里面包含了XML格式的各种工作表、样式等文件。这个区别直接决定了库的选择。下面这个表格是我根据多年经验整理的库特性对比你可以快速找到适合你任务的工具库名称主要功能支持格式优点缺点典型应用场景pandas数据分析读写.xlsx,.xls(需引擎)接口极其简洁数据处理能力超强整合了openpyxl和xlrd。对单元格格式、图表等Excel高级功能控制较弱。数据清洗、分析、转换、批量读写。比如读取多个文件进行聚合计算。openpyxl读写、修改、创建.xlsx功能全面支持读写公式、图表、图像、样式等。不支持旧的.xls格式。处理超大文件时内存消耗需注意。需要精细控制Excel样式、公式、生成复杂报表。xlrd/xlwt读(xlrd)/写(xlwt).xls曾经是读写.xls的标准库轻量。xlrd2.0已放弃对.xls的支持仅支持.xlsx的读取。xlwt仅支持写.xls。维护遗留的.xls格式文件现在已不推荐作为新项目首选。xlwings与Excel应用程序交互.xls,.xlsx可以调用本地安装的Excel程序功能最强大能实现一切Excel手工操作。必须安装Microsoft Excel不适合无GUI的服务器环境。需要与Excel深度交互、调用宏、实现复杂自动化。pywin32/win32comWindows COM接口调用.xls,.xlsx功能比xlwings更底层控制力极强。仅限Windows系统代码较复杂。在Windows环境下进行极其底层的Excel自动化控制。注意目前社区最主流的搭配是pandasopenpyxl。pandas用于核心的数据读写和运算当需要对生成的文件进行精细的样式调整时再使用openpyxl进行后处理。对于纯.xls文件可以考虑使用xlrd1.2.0版本和xlwt但长远来看建议将文件转换为.xlsx格式。2.2 环境搭建与库安装实操选好了库下一步就是安装。我强烈建议使用虚拟环境来管理你的Python项目这能避免不同项目间的库版本冲突。这里以最常用的pandas和openpyxl为例。# 1. 创建并激活虚拟环境以venv为例 python -m venv excel_env # 创建名为excel_env的虚拟环境 # Windows: excel_env\Scripts\activate # macOS/Linux: source excel_env/bin/activate # 2. 安装核心库 pip install pandas openpyxl # 3. 可选安装xlrd用于兼容旧版.xls读取但注意版本 pip install xlrd1.2.0 # 指定安装支持.xls的老版本安装完成后可以在Python交互环境中验证一下import pandas as pd print(pd.__version__) import openpyxl print(openpyxl.__version__)实操心得如果你在安装pandas时遇到编译错误特别是在Windows上一个省事的办法是直接安装预编译的轮子wheel。可以使用pip install pandas --prefer-binary或者去 这个非官方网站 下载对应版本的.whl文件进行离线安装。对于团队协作项目务必使用pip freeze requirements.txt命令生成依赖清单确保大家环境一致。3. 使用Pandas进行高效数据读写pandas是Python数据科学生态的核心其DataFrame数据结构非常适合处理表格型数据。用它来读写Excel代码简洁到令人发指。3.1 基础读写read_excel与to_excel假设我们有一个名为销售数据.xlsx的文件里面有一个“一季度”工作表。读取Excel文件import pandas as pd # 最简单的方式读取第一个工作表 df pd.read_excel(销售数据.xlsx) print(df.head()) # 查看前5行 # 指定工作表名读取 df pd.read_excel(销售数据.xlsx, sheet_name一季度) # 指定工作表位置读取索引从0开始 df pd.read_excel(销售数据.xlsx, sheet_name0) # 只读取特定列例如‘产品名’和‘销售额’ df pd.read_excel(销售数据.xlsx, usecols[产品名, 销售额]) # 跳过文件开头几行比如表头有合并单元格等无用行 df pd.read_excel(销售数据.xlsx, skiprows2) # 设置某列为索引 df pd.read_excel(销售数据.xlsx, index_col日期)pd.read_excel函数有几十个参数上面是最常用的几个。sheet_name可以是名称、索引甚至是一个包含多个名称/索引的列表用于一次性读取多个工作表。写入Excel文件# 将一个DataFrame写入Excel默认保存为‘Sheet1’ df.to_excel(输出结果.xlsx, indexFalse) # indexFalse表示不写入行索引 # 写入到指定的工作表 df.to_excel(输出结果.xlsx, sheet_name汇总, indexFalse) # 写入多个DataFrame到同一个Excel的不同工作表 with pd.ExcelWriter(多表输出.xlsx) as writer: df1.to_excel(writer, sheet_nameSheet1, indexFalse) df2.to_excel(writer, sheet_nameSheet2, indexFalse)这里的关键是pd.ExcelWriter它作为一个上下文管理器确保所有数据都写入后才保存和关闭文件比多次调用to_excel更高效、安全。3.2 高级技巧与性能优化当处理的数据量变大或者有特殊需求时基础操作可能不够用。处理大型文件如果Excel文件很大比如几十上百MB直接读取可能内存溢出。pandas提供了分块读取的功能。# 分块读取每次读入10000行 chunk_size 10000 chunks [] for chunk in pd.read_excel(大型数据.xlsx, chunksizechunk_size): # 对每一块数据进行处理例如过滤 filtered_chunk chunk[chunk[销售额] 1000] chunks.append(filtered_chunk) # 将所有处理后的块合并 df_processed pd.concat(chunks, ignore_indexTrue)更优的做法是在循环体内直接处理并写入到另一个文件或数据库而不是先存储在列表里这样可以进一步降低内存峰值。读取时处理数据类型和缺失值Excel单元格的数据类型有时很混乱数字可能被读成字符串。我们可以在读取时就进行规范。df pd.read_excel(数据.xlsx, dtype{员工ID: str, 单价: float}, # 指定列数据类型 na_values[NA, NULL, --]) # 将特定字符串识别为缺失值NaN指定dtype可以提升读取速度和内存效率并避免后续的类型转换错误。写入时控制格式通过引擎虽然pandas不擅长直接控制样式但可以通过指定写入引擎并配合ExcelWriter的引擎参数为后续的样式调整打开大门。with pd.ExcelWriter(格式化的输出.xlsx, engineopenpyxl) as writer: df.to_excel(writer, sheet_nameSheet1, indexFalse) # 获取openpyxl的workbook和worksheet对象进行后续样式操作 workbook writer.book worksheet writer.sheets[Sheet1] # 这里可以继续用openpyxl的API设置列宽、字体等见下一章一个常见问题当你用pandas写入包含中文的文件后用Excel打开发现中文是乱码。这通常不是pandas的问题而是Excel默认编码导致的。一个解决办法是在to_excel时指定encodingutf-8-sig参数注意to_excel本身没有这个参数需在ExcelWriter中设置。实际上更常见的解决方案是确保你的DataFrame中的字符串是Unicode并且用openpyxl引擎写入它本身能很好地处理UTF-8。如果仍有问题检查你的系统区域和Excel的语言设置。4. 使用Openpyxl进行精细化控制当你需要生成的不仅仅是一张“数据表”而是一份可以直接交付给老板或客户的、格式精美的正式报表时openpyxl就是你的不二之选。它可以控制单元格字体、颜色、边框、合并单元格、公式、甚至插入图表和图片。4.1 创建与样式设置实战让我们从头创建一个带有复杂格式的销售报表。from openpyxl import Workbook from openpyxl.styles import Font, Alignment, Border, Side, PatternFill from openpyxl.utils import get_column_letter # 1. 创建工作簿和工作表 wb Workbook() ws wb.active ws.title 销售月报 # 2. 写入标题和数据 data [ [月份, 产品A, 产品B, 产品C, 合计], [一月, 1500, 2300, 1200, SUM(B2:D2)], [二月, 1800, 2100, 1500, SUM(B3:D3)], [三月, 2200, 1900, 1800, SUM(B4:D4)], ] for row in data: ws.append(row) # 3. 设置标题行样式 title_font Font(name微软雅黑, size14, boldTrue, colorFFFFFF) title_fill PatternFill(start_color366092, end_color366092, fill_typesolid) title_alignment Alignment(horizontalcenter, verticalcenter) for cell in ws[1]: # 第一行 cell.font title_font cell.fill title_fill cell.alignment title_alignment # 4. 设置数据区域样式 thin_border Border(leftSide(stylethin), rightSide(stylethin), topSide(stylethin), bottomSide(stylethin)) for row in ws.iter_rows(min_row2, max_row4, min_col1, max_col5): for cell in row: cell.border thin_border if isinstance(cell.value, (int, float)): cell.number_format #,##0 # 千位分隔符格式 cell.alignment Alignment(horizontalright) # 5. 设置“合计”列字体加粗 for row in range(2, 5): ws[fE{row}].font Font(boldTrue) # 6. 自动调整列宽近似 for column in ws.columns: max_length 0 column_letter get_column_letter(column[0].column) # 获取列字母 for cell in column: try: if len(str(cell.value)) max_length: max_length len(str(cell.value)) except: pass adjusted_width (max_length 2) ws.column_dimensions[column_letter].width adjusted_width # 7. 保存文件 wb.save(精美销售月报.xlsx)这段代码演示了从创建、写入数据、设置字体颜色填充、边框、数字格式、公式到调整列宽的全过程。openpyxl的样式对象Font,Alignment等需要先创建再赋值给单元格的对应属性。4.2 操作现有文件与高级功能更多时候我们是修改一个已有的模板文件。from openpyxl import load_workbook # 加载现有工作簿 wb load_workbook(模板.xlsx) ws wb[数据页] # 在特定位置写入数据 ws[C10] 2024 # 在C10单元格写入 ws.cell(row15, column5, value审核通过) # 在第15行第5列即E15写入 # 遍历和修改数据 for row in ws.iter_rows(min_row2, max_col3, values_onlyFalse): # row是一个包含Cell对象的元组 product_cell, sales_cell, flag_cell row if sales_cell.value and sales_cell.value 10000: flag_cell.value 达标 flag_cell.font Font(color00FF00) # 绿色字体 # 插入一行 ws.insert_rows(5) # 在第5行前插入一个空行 # 插入一列 ws.insert_cols(3) # 在第3列前插入一个空列 # 合并单元格 ws.merge_cells(A1:E1) # 合并A1到E1 merged_cell ws[A1] merged_cell.value 年度销售总报表 merged_cell.alignment Alignment(horizontalcenter) # 保存为新文件避免覆盖原模板 wb.save(填充后的报表.xlsx)高级功能公式与图表openpyxl支持写入Excel公式计算会在Excel打开文件时进行。ws[F2] SUM(B2:E2) # 写入求和公式创建图表相对复杂需要引入openpyxl.chart子模块并定义数据系列和图表类型如BarChart,LineChart。由于步骤较多核心思路是创建图表对象 - 定义数据范围Reference - 创建数据系列Series并添加到图表 - 将图表添加到工作表指定位置。一个关键注意事项openpyxl在load_workbook时默认不会读取公式的计算结果只会读取公式本身cell.value显示为SUM(...)。如果你需要获取上次保存时计算好的值必须在加载时指定data_onlyTruewb load_workbook(文件.xlsx, data_onlyTrue)。此时cell.value将是计算结果一个数字但你无法再获得公式本身。根据你的需求谨慎选择模式。5. 实战案例批量处理与自动化报表生成现在我们把前面学的知识串起来解决一个真实场景的问题每日自动合并多个销售明细Excel文件并生成带格式的汇总日报。假设场景每天各区域销售团队会提交一个以“区域_日期.xlsx”命名的文件如“华北_20240515.xlsx”存放在./daily_reports/文件夹下。每个文件结构相同都有“销售明细”工作表。我们需要写一个脚本自动合并这些文件计算各产品总销售额并生成一个格式美观的汇总日报。5.1 项目结构与核心代码project/ ├── daily_reports/ # 存放每日区域报告 │ ├── 华北_20240515.xlsx │ ├── 华东_20240515.xlsx │ └── 华南_20240515.xlsx ├── config.py # 配置文件如路径、列名映射 ├── merge_reports.py # 主脚本 └── templates/ # 存放输出报表模板 └── daily_summary_template.xlsxmerge_reports.py主脚本import os import pandas as pd from openpyxl import load_workbook from datetime import datetime import config # 假设config.py里定义了路径常量 def merge_daily_reports(report_date): 合并指定日期的所有区域报告 report_dir config.REPORTS_DIR all_data_frames [] # 1. 遍历文件夹找到对应日期的所有区域文件 for filename in os.listdir(report_dir): if report_date in filename and filename.endswith(.xlsx): filepath os.path.join(report_dir, filename) region filename.split(_)[0] # 提取区域名 try: # 使用pandas读取 df pd.read_excel(filepath, sheet_nameconfig.SHEET_NAME) # 添加一列标识区域 df[区域] region all_data_frames.append(df) print(f成功读取: {filename}) except Exception as e: print(f读取文件 {filename} 时出错: {e}) if not all_data_frames: print(f未找到 {report_date} 的报告文件。) return None # 2. 合并所有DataFrame merged_df pd.concat(all_data_frames, ignore_indexTrue) # 3. 数据清洗与计算 # 确保金额列为数值类型 merged_df[config.SALES_AMOUNT_COL] pd.to_numeric(merged_df[config.SALES_AMOUNT_COL], errorscoerce) # 填充可能的空值 merged_df.fillna({config.PRODUCT_COL: 未知, config.SALES_AMOUNT_COL: 0}, inplaceTrue) # 4. 按产品汇总 summary_df merged_df.groupby(config.PRODUCT_COL, as_indexFalse).agg({ config.SALES_AMOUNT_COL: sum, 区域: lambda x: , .join(sorted(set(x))) # 列出有销售的区域 }) # 重命名列 summary_df.columns [产品, 总销售额, 销售区域] # 按销售额降序排序 summary_df.sort_values(by总销售额, ascendingFalse, inplaceTrue) return summary_df, merged_df def generate_summary_report(summary_df, raw_df, report_date): 将汇总数据填入模板生成格式化的日报 # 1. 加载模板文件 template_path config.TEMPLATE_PATH wb load_workbook(template_path) ws_summary wb[汇总] ws_detail wb[明细] # 2. 写入汇总数据 # 从模板第5行开始写前4行是标题等 start_row 5 for i, row in summary_df.iterrows(): ws_summary.cell(rowstart_row i, column1, valuerow[产品]) ws_summary.cell(rowstart_row i, column2, valuerow[总销售额]) ws_summary.cell(rowstart_row i, column3, valuerow[销售区域]) # 设置数字格式为货币 ws_summary.cell(rowstart_row i, column2).number_format ¥#,##0.00 # 3. 写入明细数据可选 # 可以按需将raw_df写入ws_detail工作表此处省略... # 4. 更新报表标题中的日期 ws_summary[A1] f销售日报 - {report_date} # 5. 保存为新文件 output_dir config.OUTPUT_DIR os.makedirs(output_dir, exist_okTrue) output_filename f销售日报_汇总_{report_date}.xlsx output_path os.path.join(output_dir, output_filename) wb.save(output_path) print(f日报已生成: {output_path}) return output_path if __name__ __main__: # 假设处理昨天的报告日期格式为YYYYMMDD today datetime.now() yesterday today.replace(daytoday.day-1) report_date yesterday.strftime(%Y%m%d) # 例如20240515 summary_data, raw_data merge_daily_reports(report_date) if summary_data is not None: generate_summary_report(summary_data, raw_data, report_date) else: print(无数据可处理程序退出。)5.2 脚本优化与部署建议上面的脚本已经可以工作但在生产环境中还需要考虑更多。错误处理与日志增加更细致的try...except块捕获并记录每一种可能的错误文件损坏、格式不对、列名缺失等。使用Python的logging模块替代print将运行日志输出到文件方便排查。性能优化如果区域文件非常多比如上百个pd.concat在循环中追加可能不是最高效的。可以先将所有文件路径存入列表然后用pd.read_excel配合列表推导式一次性读取所有DataFrame再用一个pd.concat合并。参数化与配置将日期、文件路径、列名等全部放入config.py或通过命令行参数传入使脚本更灵活。# config.py 示例 REPORTS_DIR ./daily_reports OUTPUT_DIR ./summary_reports TEMPLATE_PATH ./templates/daily_summary_template.xlsx SHEET_NAME 销售明细 PRODUCT_COL 产品名称 SALES_AMOUNT_COL 销售额自动化调度在Linux服务器上可以使用cron定时任务在Windows上可以使用“任务计划程序”。让脚本每天凌晨自动运行实现真正的“无人值守”报表自动化。模板设计提前用Excel设计好daily_summary_template.xlsx定义好所有的格式、公式如总计、平均值、图表。脚本只需要向指定位置“灌入”数据即可这样可以生成非常专业的报表。我踩过的一个坑在向模板写入数据时如果数据行数不固定可能会覆盖模板原有的底部公式如总计行。我的解决方案是在模板中把总计行放在一个固定的、足够靠下的位置比如第100行并用OFFSET或INDEX函数定义动态求和范围。或者在脚本中先计算出行数再动态调整模板中公式引用的范围。6. 疑难杂症与解决方案速查在实际操作中你肯定会遇到各种各样奇怪的问题。这里我整理了一份“踩坑实录”希望能帮你快速排雷。6.1 常见报错与原因分析报错信息可能原因解决方案ModuleNotFoundError: No module named pandas未安装pandas或在错误的Python环境中运行。激活正确的虚拟环境运行pip install pandas。ImportError: Missing optional dependency openpyxl使用pandas读写.xlsx但未安装openpyxl。运行pip install openpyxl。对于.xls可能需要xlrd。PermissionError: [Errno 13] Permission denied要写入的文件正被其他程序如Excel打开。关闭Excel或其他占用该文件的程序。BadZipFile: File is not a zip file文件扩展名是.xlsx但实际不是有效的Excel文件或文件已损坏。检查文件是否完整尝试用Excel手动打开。或用file命令Linux/Mac检查文件类型。KeyError: “工作表名不存在”sheet_name参数指定的工作表名称错误或不存在。先用pd.ExcelFile(file).sheet_names或openpyxl的wb.sheetnames查看所有工作表名。写入后数字变成科学计数法或日期变成数字Excel单元格格式未正确设置。用openpyxl写入时显式设置单元格的number_format如‘YYYY-MM-DD’或‘0.00’。中文字符显示为乱码文件编码问题或字体不支持。确保系统/Excel语言支持。用openpyxl时单元格值使用Python Unicode字符串。检查生成文件的Excel默认字体是否包含中文字体。pandas读取速度非常慢文件过大或包含大量公式、格式。尝试read_excel时指定engineopenpyxl和data_onlyTrue如果不需要公式。考虑将文件另存为.csv处理或使用分块读取。用openpyxl保存后公式不见了默认情况下openpyxl不会保留其他程序如Excel写入的公式除非你显式地以公式形式写入。确保你写入单元格的值是以开头的字符串如ws[A1] SUM(B1:B10)。6.2 性能优化与最佳实践最小化读写操作最耗时的部分是磁盘I/O。尽量避免在循环中反复读写Excel文件。最佳模式是一次性将所有数据读入DataFrame- 在内存中进行所有计算和操作 - 一次性写入结果。善用data_only模式如果你只需要最终数值而不关心公式用openpyxl加载时使用load_workbook(filename, data_onlyTrue)可以跳过公式解析大幅提升读取速度。关闭不必要的属性计算openpyxl的Workbook对象在加载时会计算一些属性如公式。如果不需要可以在加载后设置wb._archive等属性来优化但这属于高级技巧。对于一般应用data_onlyTrue已经足够。对于超大型文件如果文件大到内存无法容纳考虑使用pandas的chunksize参数分块读取处理。将Excel文件导入数据库如SQLite进行处理。评估是否必须使用Excel格式.csv或.parquet格式在处理速度上有数量级的优势。版本兼容性明确你的用户使用什么版本的Excel。openpyxl对Excel 2010的支持最好。如果必须支持旧的.xls就不得不使用xlrd1.2.0版和xlwt但它们功能有限且不再活跃维护。最后我个人最推荐的工作流是用pandas做所有脏活累活数据读取、清洗、计算、转换用openpyxl做最后的“梳妆打扮”格式、样式、图表。这两个库的组合几乎能应对所有Python处理Excel的自动化需求。当你熟练之后你会发现以前需要加班几个小时才能完成的报表工作现在喝杯咖啡的时间脚本就跑完了。这就是编程带来的效率革命。
返回列表