Python操作Excel库选型指南:openpyxl、pandas、xlsxwriter实测对比

发布时间:2026/10/11 4:52:54
Python操作Excel库选型指南:openpyxl、pandas、xlsxwriter实测对比 上个月接了个挺典型的需求要把公司散落在十几个文件里的订单数据汇总成一张带格式的月报还要保留原模板的表头样式。我第一反应是用 pandas 一把梭结果被模板样式、合并单元格、数字格式这些细节磨了两天。后来重新把几个常用的操作Excel库横向拉了一遍才发现问题的本质不是“哪个库最厉害”而是“你这个具体场景到底该用哪个库”。这篇文章我就把自己实测的结果和选型思路完整写出来希望能帮你少走点弯路。我不打算只丢一张对比表了事。选错库的代价往往不是安装时发现的而是等你写完几百行脚本、跑到一半才报错时才意识到。所以这篇文章会按“需求判断 - 读 - 写 - 性能 - 兼容性 - 最终选型”这个顺序来展开每个环节都会给出实际能跑的代码和踩过的坑。1. 选库之前必须想清楚的四件事先说结论Excel相关的库没有一个能通吃所有场景。原因很简单Excel文件本身就混合了“数据”和“排版”两种完全不同的东西而市面上这些库各有侧重。1.1 先分清“表格工具”和“数据处理工具”两条路线我第一次接触 openpyxl 的时候以为它就是个“读写Excel的库”pandas 也是那随便选一个不就行了真上手之后才发现它们解决问题的层级完全不同。openpyxl、xlsxwriter、xlrd 这一族是直接跟 .xlsx / .xls 文件格式打交道的“表格工具”。它们能控制单元格地址、字体、边框、列宽、合并单元格、条件格式说白了就是把Excel当作一个“格式文档”来操作。而 pandas 不是表格工具它是“数据处理工具”DrivingLicense只是把 Excel 当成了数据的出入口。你给 pandas 一个 DataFrame它能把数据写进 sheet也能从 sheet 读成 DataFrame但它不关心表头颜色标不标准、数字要不要显示成千分位。这两条路线没有优劣但你必须先搞清楚自己是哪一类需求。如果需求是“把数据库里的结果导出成一张Excel报告领导要看格式”那核心工具应该选 xlsxwriter 或 openpyxl如果需求是“把Excel里的几千行数据读进来做透视、筛选、算数”那你真正需要的是 pandas读文件只是它的前置步骤。1.2 读、写、改、样式四类需求决定选型方向我在实际项目里会把需求拆成四类每一类的选型优先级完全不同。纯读取程序要从Excel里拿数据去做别的事格式不重要。常见场景是数据导入、ETL、报表源数据采集。批量写入把程序算好的数据批量写进Excel格式基本不用管。常见场景是数据导出、备份、接口返回落地。修改已有文件打开一个现成的Excel模板往指定单元格填值然后另存。常见场景是填合同、填报销单、生成带模板样式的月报。从零生成带样式的报表不仅要写数据还要设置字体、颜色、边框、图表、条件格式。常见场景是经营分析报表、财务对账单。如果你是“纯读取”用 pandas 可能很爽但遇到超大文件容易被内存卡死如果你是“修改已有文件”pandas 根本不适合因为它在保存时会重写整个sheet模板样式大概率保不住。这些细节后面细讲但“四类需求”这步先想清楚能帮你筛掉一半不合适的库。还有一个容易忽略的点.xls 和 .xlsx 是两个时代的产物。.xls 是微软老一代二进制格式.xlsx 是 OOXML 规范下的 zipXML 格式。很多库的定位差异就体现在这里比如 xlrd 2.0 之后只支持 .xlsopenpyxl 只支持 .xlsx。做选型之前先看一眼手头的文件后缀能省掉一堆莫名其妙的报错。2. 主流操作Excel库一次看完2.1 横评对象与各自的市场定位我这次对比的库一共五个openpyxl、pandas、xlsxwriter、xlrd/xlwt/xlutils 这套老组合、以及 pyexcel。这五个基本覆盖了 Python 生态里 95% 的Excel操作场景。openpyxl是目前社区最活跃的库读写 .xlsx / .xlsm样式控制能力强能做图表、条件格式、图片而且支持读取已有文件再修改。它的问题是性能偏中等处理几十万行时会明显变慢。pandas严格说不是Excel库但它通过read_excel/to_excel接口封装了 openpyxl 和 xlsxwriter是目前大多数人实际接触Excel的入口。它的优势是数据变换能力强劣势是格式控制弱、大文件内存占用高。xlsxwriter是一个“只写不读”的库专门用来从零生成 .xlsx。它的性能非常好样式、图表、条件格式、富文本几乎全支持是生成报表类文件的最佳选择之一。代价是你不能拿它打开已有文件修改。xlrd / xlwt / xlutils是处理 .xls 老格式的老牌组合。xlrd 负责读xlwt 负责写xlutils 负责在两者之间做复制修改。现在它们更多是历史包袱新项目一般不建议优先选。pyexcel是“统一接口”思路的库能用同一套 API 读写 csv、xls、xlsx、ods 等多种格式底层通过插件调用其他库。好处是代码简单坏处是复杂功能如图表、复杂样式覆盖不完整。2.2 一张表看清五个库的边界下面是基于我的实际使用情况做的横向对比参数只针对常规操作不含极限优化。能力openpyxlpandas openpyxlxlsxwriterxlrd/xlwtpyexcel读取 .xlsx支持支持不支持2.0后不支持支持插件读取 .xls不支持需配合 xlrd不支持支持支持插件写入 .xlsx支持支持支持不支持支持插件写入 .xls不支持不支持不支持支持支持插件修改已有文件支持弱另存重写不支持通过 xlutils弱单元格样式较强极弱强一般弱合并单元格支持只能写不能灵活读支持支持支持条件格式支持不支持强不支持不支持图表支持基础不支持强不支持不支持大数据量写入性能中等较好好中等中等大数据量读取性能支持只读流式内存占用高不支持老格式整体加载依赖底层这张表想说明一个核心观点每个库都有自己的强项和明确边界。比如你看到 openpyxl 能修改已有文件就以为它一定能完美保留模板里的数据验证下拉框实际测试下来并不一定你看到 pandas 写Excel很快但把它当成修改模板的工具就基本没法用。3. 读取数据时的实际选择读取Excel是日常开发里最基础也最容易踩坑的环节。这里不聊理论直接说我在真实项目里怎么选。3.1 openpyxl 的 read_only 模式才是大文件读入的正道用 openpyxl 读 .xlsx 时默认行为是把整个工作簿加载进内存这对于十几MB的小文件没什么问题但一旦碰到几十MB的导表文件加载过程会变得又慢又吃内存。openpyxl 提供了一个read_onlyTrue的流式读取模式它不会一次性把整个 sheet 的 XML 解析完而是按行返回数据。我处理 50MB 左右的 .xlsx 文件时普通模式直接内存涨到 1GB 以上换成只读模式后内存占用下降了 80% 左右。from openpyxl import load_workbook # data_onlyTrue 拿公式的缓存值read_onlyTrue 走流式 wb load_workbook(big_file.xlsx, read_onlyTrue, data_onlyTrue) ws wb[订单明细] for row in ws.iter_rows(values_onlyTrue): # row 是一个元组按列顺序取值 order_id row[0] customer row[1] amount row[2] # 在这里做你的业务处理不要试图把整个 sheet 装进列表 pass wb.close()需要留意的是read_onlyTrue模式不支持随机访问任意单元格你只能顺序遍历它也不适合“先读后改再保存”这种场景。如果你的需求是想修改文件必须用普通模式把工作簿完整加载进来。3.2 xlrd 处理 .xls 老文件的两个版本陷阱我自己维护过一个老项目里面有一段读 .xls 的代码用了 xlrd一直好好的。某天新同事重新装了依赖代码直接报xlrd.biffh.XLRDError: Excel xlsx file; not supported。这个报错的来源就是 xlrd 2.0 之后把 .xlsx 支持移除了只保留 .xls。如果你的环境和历史代码里用的是新版本 xlrd又拿它去读 .xlsx就会立刻报错。处理老文件时正确的做法是import xlrd book xlrd.open_workbook(legacy_file.xls) sheet book.sheet_by_index(0) for r in range(sheet.nrows): row_values sheet.row_values(r) print(row_values)这里还有两个常见坑。第一sheet.nrows只能拿到文件里实际有数据的行数但偶尔会遇到整列有格式没数据的情况行数会被虚报第二如果你项目里有大量历史代码依赖 xlrd 读 .xlsx请在 requirements 里锁版本xlrd1.2.0否则升级之后会引发连锁报错。3.3 data_onlyTrue 的副作用公式结果并不总是拿得到openpyxl 读取带公式的单元格时有个让人很困惑的行为同样是load_workbook不传data_only时单元格的值是公式字符串比如SUM(A1:A10)传了data_onlyTrue时拿到的才是缓存的公式计算结果。问题在于这个“缓存结果”是 Excel 或 WPS 保存文件时写进文件里的。如果你的 .xlsx 是程序直接生成的中间从来没经过 Excel 打开保存那data_onlyTrue可能返回None因为文件里根本不存在计算结果缓存。我踩过一次很深的坑一个报表脚本用 xlsxwriter 生成了带SUM公式的文件然后另一个脚本用 openpyxl 的data_onlyTrue去读它结果所有公式单元格全是空。后来我把生成端改成了“先写数值再在需要公式的单元格写入公式”并让文件经过一次 Excel 打开保存才彻底解决。如果你一定要在 Python 里拿到公式的真正计算结果可以考虑用独立公式计算引擎对公式求值但复杂度明显上升。常规项目里我的经验是生成文件的源头尽量同时保存数值读取端默认data_onlyTrue双保险。4. 写入与样式openpyxl 和 xlsxwriter 的正面较量写入场景下最让开发者纠结的就是 openpyxl 和 xlsxwriter 怎么选。我的结论是修改模板选 openpyxl从零生成精美报表选 xlsxwriter。下面用两个案例说清楚。4.1 用 openpyxl 做模板填充的核心逻辑如果要填充的是一个手动排好版的 Excel 模板比如“月度经营分析表”里面已经有公司Logo、固定的表头、合并单元格、预设的边框和列宽那正确的做法是用 openpyxl 按原路径打开只往里填数据然后另存。from openpyxl import load_workbook from datetime import date wb load_workbook(月度经营模板.xlsx) ws wb[收入明细] # 假设模板第3行开始是数据区已经预设了表头样式 ws[A3] 2025-06-01 ws[B3] 华东区 ws[C3] 128000.50 wb.save(月度经营_202506.xlsx)这段代码看起来很简单但有一个重要前提load_workbook默认会把工作簿完整读进内存同时把每个单元格对象和样式对象都搭好。所以模板文件越大这个操作越慢也越容易内存暴涨。我建议模板文件控制在 5MB 以内数据量大的场景不要直接拿模板往里填而是先用 xlsxwriter 生成基础数据再用 openpyxl 做最终包装。另一个经验是openpyxl 保存文件后公式并不会重新计算它只是把公式文本和原缓存值原样写回去。所以如果你的模板里有跨 sheet 公式又不希望用户打开时看到旧值建议在流程末尾用 Excel 程序或接口打开一下或者干脆在模板里就避免复杂的跨工作簿引用。4.2 用 xlsxwriter 从零生成带条件的报表如果需求是“根据数据动态生成一张完整报表”没有现成模板那我强烈建议用 xlsxwriter。它对格式的处理非常高效可以从零构造一个专业级别的报表表头填充色、资金数字格式、冻结窗格、筛选按钮、条件格式全都能通过 API 直接设置。import xlsxwriter workbook xlsxwriter.Workbook(经营报表.xlsx) worksheet workbook.add_worksheet(月度汇总) header_fmt workbook.add_format({ bold: True, font_color: white, bg_color: #4472C4, border: 1, align: center, valign: vcenter, }) money_fmt workbook.add_format({ num_format: #,##0.00, border: 1, }) warn_fmt workbook.add_format({ bg_color: #FFC7CE, font_color: #9C0006, }) headers [区域, 销售额, 目标值] worksheet.write_row(A1, headers, header_fmt) # 模拟两行数据 worksheet.write(A2, 华东区) worksheet.write(B2, 128000.5, money_fmt) worksheet.write(C2, 150000.0, money_fmt) worksheet.write(A3, 华南区) worksheet.write(B3, 89000.0, money_fmt) worksheet.write(C3, 100000.0, money_fmt) # 销售额低于目标值的一行标红 worksheet.conditional_format( B2:B3, {type: cell, criteria: , value: {type: cell, criteria: , value: C2, format: warn_fmt}})不要被网上一些说法吓住这个库不是“不能读文件就代表它弱”。它的设计哲学很明确只当你需要生成新文件时使用。因为它不需要读文件底层可以按流式方式直接写 XML所以性能和内存表现都很好这也是我生成大量报表时首选它的原因。4.3 只写不读的库和只读不写的库怎么配合很多人会问xlsxwriter 不支持读那我想修改它生成的文件怎么办实际工作中我的做法是“分阶段使用不同库”。阶段一用 xlsxwriter 从零生成原始数据文件和基础样式。阶段二用 openpyxl 读取这个文件做增量修改比如往指定 sheet 加统计结果、加批注。阶段三如果还需要做数据透视再交给 pandas 处理。这样安排的好处是每个库都在自己最强的领域发挥作用。但要注意openpyxl 打开 xlsxwriter 生成的文件时某些高级特性比如极复杂的条件格式规则、部分图表对象可能解析不完整。我的建议是生成端尽量使用常用功能复杂功能做一次“另存为 excel 标准格式”的验证。5. 大数据量性能实测慢的不是库是你没找对模式很多开发者在网上抱怨 openpyxl 写入慢十有八九是用了普通模式逐格写入这个结论我在自己的机器上重新验证了一遍。5.1 我跑的十万行写入对比我构造了一份 10 万行、20 列的测试数据包含文本、数字、日期三种类型分别用几个方案生成 .xlsx内存和耗时数据如下普通办公电脑仅看量级方案耗时说明openpyxl 普通模式逐格写入约 35 秒逐格 write 非常慢内存也高openpyxl write_only 模式批量写入约 12 秒大幅提升但仍为中等水平pandas openpyxl约 8 秒DataFrame.to_excel 走块级写入xlsxwriter约 4 秒流式生成性能最优pyexcel xlsxwriter 插件约 5 秒接近 xlsxwriter 原生这个结果说明一个很简单的道理逐格操作和批量操作的性能差距是数量级的。如果你要用 openpyxl 写大量数据就不要在循环里反复cell.value xxx。这里是一个 write_only 模式的正确姿势from openpyxl import Workbook wb Workbook(write_onlyTrue) ws wb.create_sheet(data) # 直接 append 整行内部按块写入比逐格赋值快很多 for i in range(100000): ws.append([i, f文本{i}, 12345.67, 2025-06-01]) wb.save(output.xlsx)5.2 读取大文件时别让 pandas 一次性吞进内存与写入类似pandas 的read_excel很方便但它本质上是把整个 sheet 读成 DataFrame全部驻留在内存里。我处理过一张 80 万行的明细表用 pandas 读入后内存占用直接超过 2GB之后再做任何数据变换都极其吃力。这种情况下我的首选是 openpyxl 的read_only模式配合 Python 生成器逐行处理把数据边读边转成目标结构。虽然代码没有 pandas 一行搞定那么简洁但内存占用可以稳定控制在几百 MB 以内。如果确实想让 pandas 吃下大文件可以分块读先记录总行数再用skiprows和nrows分段读取最后拼起来。这种方式牺牲了一些速度但能把内存峰值压下来。5.3 什么数据量该用哪种组合这里有一个我自己的经验分界线不一定是绝对标准但可以帮新手上路1 万行以内openpyxl 普通模式完全够用代码简单好维护。1 万到 10 万行openpyxl 的 write_only 模式或 pandas openpyxl。10 万行以上优先 xlsxwriter如果需要 DataFrame就用 pandas xlsxwriter 引擎。读取超大 Excel绝对优先 openpyxl 的 read_only 模式。如果你的数据量到了百万行级别我甚至建议换个思路先让程序把 Excel 转成 csv 或数据库再处理。Excel 本身不适合作为百万行数据的介质硬上一个库也解决不了根本瓶颈。6. 格式保留与兼容性那些文档里没写的坑写 Excel 跟写普通数据文件最大的不同就是格式。这里有不少是文档不会告诉你的但实际项目里特别容易翻车。6.1 合并单元格读取时只有左上角有值读取带合并单元格的 sheet 时openpyxl 只会给合并区域的左上角单元格赋实际值其余单元格读出来是None。如果你直接按行遍历会漏掉大量信息。我的处理方式是先检查ws.merged_cells.ranges拿到所有合并区域然后手动把左上角的值填充到整个区域from openpyxl import load_workbook wb load_workbook(merged.xlsx) ws wb.active # 收集所有合并区域 merge_map {} for m_range in list(ws.merged_cells.ranges): top_value ws.cell(m_range.min_row, m_range.min_col).value for row in range(m_range.min_row, m_range.max_row 1): for col in range(m_range.min_col, m_range.max_col 1): merge_map[(row, col)] top_value这种做法在报表解析、对账系统里非常实用。我曾在某个数据迁移项目里因为漏了这一步结果合并单元格下面的一大片区域全变成了空数据最终对账差了十几万。6.2 条件格式和数据验证在不同环节的保留情况openpyxl 可以读取部分条件格式规则但遇到复杂规则图标集、三色刻度、数据条时不同版本表现不一致。xlsxwriter 写条件格式很轻松但它只写不读所以不存在“读取保留”的问题。真正容易踩坑的是模板文件另存。我给客户做过一个合同模板里面有一列是“合同状态”设置了数据验证下拉框和条件格式。第二次打开时 openpyxl 往里填了数据并另存结果发现下拉框还能用但某些单元格的条件格式变乱了。原因是一些下拉框关联的是“同一工作表内的名称区域”另存时引用区域发生了偏移。所以我的经验是模板文件在交付前一定先用业务里真实会用到的全流程跑一遍检查样式、下拉、格式是否都符合预期。别等最后生成完才发现问题。6.3 数字格式和日期序列号的常见混淆Excel 内部把日期存成序列号比如 2025-06-01 在单元格里的本质是一个数字。如果你用 openpyxl 写入 Python 的 datetime 对象它会自动转换成日期类型但如果你从别处拿到的是一个普通数字直接写入就会变成45609这种“裸数字”。正确的做法是写入后单独设置数字格式from openpyxl.styles import numbers cell ws[B2] cell.value 45609 cell.number_format numbers.FORMAT_DATE_YYYYMMDD2 # yyyy-mm-ddxlsxwriter 的做法不太一样它有专门的write_datetime方法需要传入 datetime 对象和格式对象import datetime as dt date_fmt workbook.add_format({num_format: yyyy-mm-dd}) worksheet.write_datetime(A1, dt.datetime(2025, 6, 1), date_fmt)很多报表生成脚本跑完发现日期列全是数字就是因为忘了设置number_format。这个坑特别小但几乎每个新手都会踩一次。7. 最终选型建议与我的使用习惯7.1 一张决策表覆盖八成需求如果你看到这里还是有点乱可以直接用下面这张决策表做选型基本覆盖常规项目的需求需求场景推荐方案关键理由读 .xlsx文件不大pandas.read_excel简单直接读 .xlsx文件很大openpyxl read_only内存可控读 .xls 老文件xlrd锁 1.2.0唯一稳定支持把 DataFrame 写进 Excelpandas xlsxwriter速度与统计能力平衡修改模板文件并保留样式openpyxl唯一可读写改样式的稳定组合从零生成带图表条件的报表xlsxwriter性能与样式能力最优格式混杂的小项目快速处理pyexcel代码统一、简单这个表是我在多个项目里反复验证过的组合。它不保证每个极限场景最优但一定不会让你在三更半夜排查莫名报错。7.2 我沉淀下来的一些使用习惯最后分享几点我长期实践后觉得特别重要的使用习惯。第一混合使用不犯法但要清楚边界。我的一个常见组合是pandas 负责数据清洗和统计xlsxwriter 负责把结果生成漂亮报表openpyxl 负责在最后阶段打开文件做补充修改。这三个库各干各的事互不干扰问题反而最少。第二新项目一律统一用 .xlsx能不用 .xls 就不用 .xls。.xls 老格式带来的兼容性问题远多于收益。如果客户坚持给 .xls我一般会先让脚本把文件转成 .xlsx再走主流程。第三写文件之后一定要做“二次验证”。很多库生成的 .xlsx 表面看起来没问题打开时却提示损坏或样式丢失。我现在养成了一个习惯每个导出任务跑完后用 openpyxl 再打开一次生成的文件检查 sheet 数量、行数、关键单元格的值和样式是否符合预期。这一步成本很低却能提前拦下绝大多数交付事故。如果你正面临选型问题希望这篇对比能帮你一次性理清思路。代码可以直接拿去用踩坑的经验也已经标出来了剩下的就是拿真实数据跑一遍看看哪种组合最顺手。

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询