资讯动态

Python读取Excel全攻略:从zip包到pandas的高效实践

发布时间:2026/9/15 10:06:53 来源:尧图企业网站定制
简介在日常的数据处理和分析工作中批量读取Excel表格是一项出现频率很高的基础需求。这套压缩包正是针对这一需求打造的Python实战示例适合数据分析初学者、办公自动化脚本编写者以及需要从分散表格中快速汇总信息的人员。包内共包含十四个文件以十个Python脚本为核心同时附有三个XML配置文件和两个项目结构文件整体大小仅为十七KB非常轻量易读。脚本完整演示了使用os模块的listdir函数遍历目标目录、依据扩展名筛选xlsx或xls文件再通过循环调用pandas库的read_excel函数将每个工作表转换为DataFrame对象的过程同时介绍了sheet_name、usecols、nrows等参数的具体用法并针对大文件给出了chunksize分块读取的优化思路。多个脚本覆盖贵州、青岛等不同数据场景融入了数据清洗、字段筛选和简单聚合分析的实例方便读者对照修改。目前已有七百八十余人学习解压后仅需修改目录路径即可运行能够有效提升Excel批量处理与数据整理的效率是值得参考的入门级实用代码包。1. Python 读 Excel 的起点.xlsx 本身就是个 zip 包多数人在 Python 里第一次读 Excel 时会撞上一个奇怪的报错文件扩展名明明是 .xlsx错误信息里却全是 zipfile、BadZipFile 之类的字眼。这不是 Python 装坏了而是 .xlsx 的文件结构本质上就是一个 zip 压缩包里面用层级目录装着多份 XML——工作表、样式、共享字符串、主题全在里面。标题里的 python read excel.zip 恰好把这层关系挑明了你日常用 pandas 读 Excel底层其实一直在跟 zip 打交道。接下来从 read_excel 的最小命令讲起到整包 zip 里批量读 Excel、公式缓存、dtype 陷阱、加密文件和大文件低内存这些真正会卡住人的地方。刚配好 python 环境、准备把手工表格处理脚本化的从业者按这套路径走完能省下大量试错时间。2. 用 pandas 与 openpyxl 落实 python excel 读取的最小命令2.1 先确认依赖read_excel 不是 pandas 自带的pd.read_excel 看起来是 pandas 的函数但真正解析 .xlsx 文件的引擎是 openpyxl。pandas 在背后以只读方式加载 openpyxl 的 workbook再把单元格组装成 DataFrame。如果环境里只有 pandas 而没有 openpyxl一调用就会抛 ImportError: Missing optional dependency openpyxl。第一步先把依赖装齐。命令行里执行# 安装 pandas 与两个 excel 引擎 pip install pandas openpyxl xlrd如果你的网络拉取慢常见做法是切换国内镜像# 用清华镜像安装同一组依赖 pip install -i https://pypi.tuna.tsinghua.edu.cn/simple pandas openpyxl xlrd参数说明pandas 负责提供数据结构和 read_excel 入口openpyxl 负责读写 .xlsxExcel 2007 及以后xlrd 负责读取老格式 .xls。注意新版 xlrd 2.x 已经不支持 .xlsx只保留 .xls三个包各管一段不要混。刚完成 python 安装的机器上最好顺手 pip list 确认三个包都在。2.2 最少代码一行读表三行看结构拿到任何一份 .xlsx 都能立刻跑通的最短脚本import pandas as pd # 读取指定工作表第一行作为列名 df pd.read_excel(2024_sales.xlsx, sheet_name订单, header0) print(df.head(3)) print(df.dtypes)逻辑说明read_excel 打开指定文件sheet_name 定位到名为订单的工作表header0 表示把第一行当作列名。head(3) 打印前三行确认数据长什么样dtypes 打印每列推断类型这是排查后续类型问题最快的入口。read_excel 的关键参数并不难记我常用的几个整理如下参数作用常用写法sheet_name选工作表Sheet1、0第一个表、None返回全部表的 dictheader表头行号0无表头用 Noneusecols限定列范围A:C、[0, 1, 3]、[订单号,金额]dtype强制列类型{订单号: str}防止数字变浮点nrows只取前 N 行100预览大表时好用parse_dates指定日期列[下单时间]比如只读前三列、前 50 行做预览# 只读前三列和前 50 行避免一次拉全量 df_preview pd.read_excel(2024_sales.xlsx, usecolsA:C, nrows50)参数说明usecols 接受列号或列名混用容易报错建议统一用列名nrows 与 usecols 组合只影响返回结果openpyxl 内部仍然是全量解析所以它省内存有限不能当作大文件的最终方案只是让预览响应快一点。2.3 需要单元格坐标时直接用 openpyxlpandas 擅长把表变成规整的 DataFrame但当你要按坐标访问单元格、要读合并单元格信息、要保留公式时直接操作引擎更顺手from openpyxl import load_workbook # data_onlyTrue 读取公式的缓存计算值 wb load_workbook(2024_sales.xlsx, data_onlyTrue) ws wb[订单] for row in ws.iter_rows(min_row1, max_row5, values_onlyTrue): print(row)逻辑说明load_workbook 默认把公式字符串放进 cell.valuedata_onlyTrue 则读取上次保存时缓存的数值。iter_rows 按行迭代min_row/max_row 限定范围values_onlyTrue 表示只要值不要单元格对象。这段代码的输出和 pandas 的 head 类似但你能精确控制从第几行开始、读多少行。提示pandas 内部调用 openpyxl 时固定开了 data_onlyTrue。这意味着公式单元格读到的是缓存值不是实时计算结果这个特性在第四章会重点展开。3. python 读取 zip 中的 excelBytesIO 不落盘方案3.1 两种拆包路径先想清楚再动手最常见的两个场景一是业务系统按天或按月把十几张报表压缩成一个 zip 包推送下来二是别人交付数据时习惯把整个目录打成 zip里面还带着嵌套目录名。这两种情况都不必先把 zip 解压到磁盘再读。方案磁盘占用适用场景解压到临时目录再读有临时文件残留需要人工核对原始文件BytesIO 从内存直读零占用批量处理、定时任务直接在 zip 包上调用 pd.read_excel 是不能工作的因为 read_excel 的第一个参数要求是文件路径或文件对象而 ZipFile.open 返回的对象不支持任意 seekpandas 解析时需要来回定位。BytesIO 正好把这个缺口补上。3.2 先列出 zip 里的 excel 名单动手读之前先把包里的 xlsx 全部找出来import zipfile with zipfile.ZipFile(report_bundle.zip) as zf: for name in zf.namelist(): if name.lower().endswith((.xlsx, .xls)): print(name)逻辑说明namelist() 返回包内所有条目的完整路径包括目录前缀。用 endswith 过滤时注意大小写文件名可能是 REPORT.XLS所以要 lower() 后再判断。这里 .xls 和 .xlsx 一起过滤但后续读取时引擎不一样需要分别处理。3.3 核心写法zipfile 读出字节BytesIO 接住pandas 消费import zipfile import pandas as pd from io import BytesIO frames [] with zipfile.ZipFile(report_bundle.zip) as zf: for name in zf.namelist(): if not name.lower().endswith(.xlsx): continue with zf.open(name) as fp: raw fp.read() # 读出整个 xlsx 的原始字节 df pd.read_excel(BytesIO(raw), sheet_name0) df[来源文件] name # 标注每行数据来自哪个分包 frames.append(df) result pd.concat(frames, ignore_indexTrue) print(result.shape)逻辑说明zf.open(name) 返回一个只读的 ZipExtFile调用它的 read() 函数把整个 xlsx 的字节取出来。BytesIO(raw) 把字节包装成可 seek 的文件对象pandas 把它当成普通文件读取。每张表读完追加一列来源文件防止合并后不知道行来自哪里。最后 pd.concat 把所有 DataFrame 竖着拼接ignore_indexTrue 重置行号。几个值得记住的参数zf.read(name) 等价于 zf.open(name).read()但前者一次拿全量字节后者适合流式处理大条目BytesIO 不落盘处理完自动被回收concat 的 ignore_index 如果不设结果会保留原始表的行号索引后续 reset_index 多一道手续。提示如果 zip 包里的 .xls 也想读read_excel 需要显式指定 enginexlrdopenpyxl 不认老的 .xls 格式。3.4 带密码的 zip用 setpassword不碰破解如果交付方给 zip 加了密码zipfile 读取时会抛 RuntimeError: Bad password。合法场景是你手里有密码直接注册即可import zipfile, pandas as pd from io import BytesIO with zipfile.ZipFile(encrypted_bundle.zip) as zf: zf.setpassword(byour-password) # 密码必须是 bytes with zf.open(2024_sales.xlsx) as fp: df pd.read_excel(BytesIO(fp.read())) print(df.head())参数说明setpassword 接受 bytes 类型密码会作用于后续所有条目的解压。这里只讨论你有授权密码的文件。网上流传的所谓 zip 压缩包密码破解工具不在讨论范围内数据安全上不要碰这条路。3.5 pandas 读不通时退回 openpyxl 直接拆包偶尔会碰上 read_excel 报错而 openpyxl 能读的情况典型原因是文件里 sharedStrings.xml 受损或 sheet 数量异常。此时不用改整体设计只把读取入口换掉import zipfile from io import BytesIO from openpyxl import load_workbook with zipfile.ZipFile(report_bundle.zip) as zf: xlsx_name [n for n in zf.namelist() if n.endswith(.xlsx)][0] wb load_workbook(BytesIO(zf.read(xlsx_name)), read_onlyTrue, data_onlyTrue) ws wb.active for row in ws.iter_rows(values_onlyTrue): print(row)逻辑说明read_onlyTrue 让 openpyxl 用流式方式解析 XML不会一次性把整张表的结构放进内存data_onlyTrue 仍然取缓存值。这套写法在坏文件和大文件场景下往往比 pandas 更稳可以作为第三层兜底方案。4. excel 读取踩坑清单公式缓存、dtype 与大文件4.1 公式读出来是 None只有缓存值先说最容易让人怀疑人生的现象。表里明明有 SUM(A1:A10) 这样的公式pandas 读出来可能是正常数字也可能是一列 NaN。差别在于文件最后保存的人是谁如果是 Excel 或 WPS 保存的文件里会带公式的缓存值pandas 能读到数字。如果是 openpyxl 之类代码生成的且保存后从未被 Excel 打开重算缓存值缺失pandas 读到的就是 NaN。常见做法是让文件先经过一次重算再读。Linux 服务器上可以用 LibreOffice 批量计算# 无界面重算并另存为 xlsx soffice --headless --convert-to xlsx:Calc MS Excel 2007 XML --outdir /tmp/recalc 2024_sales.xlsx参数说明--headless 表示无界面运行--convert-to 指定输出格式--outdir 指定输出目录。重算后的文件再交给 pandas公式列就有值了。这个命令要求机器装了 LibreOffice纯 Python 环境下没有等价方案只能靠源头保证文件经过一次真实打开。4.2 编号变浮点、日期变字符串dtype 强制类型Excel 的单元格只有数值、文本、日期几种类型落到 pandas 里推断又走一层逻辑。最常见的几个坑现象原因处理000123 变成 123.0Excel 把它当数值存dtype{编号: str}再用 zfill 补零2024-01-01 读到是 datetimepandas 自动推断不想要就 astype(str)有空值的数字列变 float空 NaN 与 int 不能共存fillna(0) 或保留 float混合文本与数字的列变 object类型推断失败用 dtypestr 兜底一个实用的强制类型写法df pd.read_excel( 2024_sales.xlsx, dtype{编号: str, 备注: str}, # 文本列全部按字符串读 parse_dates[下单时间], # 时间列按日期解析 )参数说明dtype 里的列名必须和表头完全一致写错名字 pandas 会直接抛错parse_dates 接收列名列表先把该列按日期解析解析失败再退回原始值。这种方法比事后 astype 可靠因为源头类型就定了不会在推断阶段被污染。4.3 大文件别等 read_excelread_only 逐行消费read_csv 有 chunksize 参数可以分块迭代read_excel 没有。要处理几百 MB 的 xlsx常见做法是直接用 openpyxl 的只读模式逐行消费from openpyxl import load_workbook from itertools import islice import pandas as pd wb load_workbook(big_sales.xlsx, read_onlyTrue, data_onlyTrue) ws wb[流水] header next(ws.iter_rows(values_onlyTrue)) # 第一行当表头 while True: chunk list(islice(ws.iter_rows(values_onlyTrue), 5000)) # 每块 5000 行 if not chunk: break df pd.DataFrame(chunk, columnsheader) # 在这里对 df 做聚合或入库不要累积 print(df.shape) wb.close()逻辑说明iter_rows(values_onlyTrue) 返回生成器next 先取第一行当表头islice 每次切出 5000 行转成临时 DataFrame 处理处理完即丢峰值内存只跟一个 chunk 有关。read_onlyTrue 模式下 openpyxl 逐行解析 XML不构建完整内存模型。最后调用 wb.close() 释放文件句柄这个习惯别丢。4.4 加密的 xlsx先解密再交给 pandas带打开密码的 xlsx文件内部被加密成 EncryptedPackageopenpyxl 和 pandas 直接读都会解压失败。合法场景文件是你自己的、密码在手下先解密再读# 安装 Office 加密文件解析库 pip install msoffcrypto-tool安装完成后 import 名是 msoffcrypto注意包名带 -tool 而模块名不带。import msoffcrypto import pandas as pd from io import BytesIO decrypted BytesIO() with open(secret.xlsx, rb) as fp: office msoffcrypto.OfficeFile(fp) # 识别加密的 Office 文档 office.load_key(passwordyour-password) office.decrypt(decrypted) # 解密结果写入 BytesIO decrypted.seek(0) # 指针回到开头再交给 pandas df pd.read_excel(decrypted) print(df.head())逻辑说明OfficeFile 负责识别和处理加密结构load_key 传入密码decrypt 把解密后的字节写入 BytesIO。注意 decrypt 之后缓冲区指针停在末尾必须 seek(0) 回到开头否则 pandas 读到的是空内容。msoffcrypto 同样只用于你有权访问的文件。5. 用一个小脚本给 zip 里的 excel 做全量体检5.1 批量扫描包内每个 excel行数、耗时、校验值一屏看全把第三章的读取逻辑和第四章的容错思路合到一起写一个能重复使用的体检脚本。它遍历 zip 包内所有 xlsx逐张尝试读取记录成功与否、耗时和内容校验值import zipfile import hashlib import time import pandas as pd from io import BytesIO def scan_excel_bundle(path): with zipfile.ZipFile(path) as zf: for info in zf.infolist(): if not info.filename.lower().endswith(.xlsx): continue raw zf.read(info.filename) digest hashlib.md5(raw).hexdigest()[:8] # 内容指纹用于比对 t0 time.time() try: # 只读第一行验证文件可打开 pd.read_excel(BytesIO(raw), sheet_name0, nrows1) rows 有数据 except Exception as exc: print(f{info.filename}: 读取失败 - {exc}) continue print(f{info.filename}: {rows} | {time.time()-t0:.2f}s | md5{digest}) scan_excel_bundle(report_bundle.zip)参数说明infolist() 比 namelist() 多返回每条目的压缩信息这里只用到 filename。nrows1 表示每张表只读一行做连通性测试批量体检时速度最快md5 只对原始字节计算用来发现文件在传输环节是否变化。读失败的文件名打出来基本就是交付包里需要返工的部分。5.2 预检表名直接解析两层 zip 里的 workbook.xml最后一个提高效率的技巧想在不打开整个 excel 的前提下知道它有哪些工作表可以直接读 xlsx 内部的 xl/workbook.xml。因为 xlsx 本身就是 zip外层交付包也是 zip两层嵌套一起处理import zipfile import re from io import BytesIO # 外层是交付 zip内层是 xlsx 自身的 zip 结构 with zipfile.ZipFile(report_bundle.zip) as outer: raw outer.read(2024_sales.xlsx) with zipfile.ZipFile(BytesIO(raw)) as inner: xml inner.read(xl/workbook.xml).decode(utf-8) # 正则提取所有工作表名毫秒级返回 sheet_names re.findall(rsheet name([^]), xml) print(sheet_names)逻辑说明先在外层 zip 里读出 xlsx 的字节再把它当作内层 zip 打开读取 xl/workbook.xml。正则提取 sheet 标签的 name 属性即可得到工作表名清单。这个操作只解出一个小 XML比 load_workbook 快两个数量级很适合在脚本开头做一次决定后续是按 sheet_name 精准读取还是全量读。实测一张十万行的表这种预检是毫秒级的。把 scan_excel_bundle 挂到每周的定时任务里配合表名预检任何一张表格式坏了、文件被改动、sheet 数量异常都能在日志里第一时间暴露。这套流程不需要额外框架纯标准库加 pandas 就能跑日志里每行对应一张表的状态后续要加列数校验或行数比对直接在 try 块里扩展即可。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价