多数人搜「Python读取Excel」,真正卡住的往往不是不会写 pd.read_excel(),而是不知道自己停在哪一步:是引擎没装、工作表选错、表头行不对,还是文件本身大到读一次要等很久。要能判断,得先能核对:拿到 sheet_names、shape、columns、dtypes 这四个可见输出,再决定继续往下做还是回头修参数。
读取Excel的最小可核对路径是:先确认 pandas 与对应引擎装好,用pd.ExcelFile列出工作表名,再按sheet_name、header、usecols明确读入,最后用shape、columns、dtypes三项输出比对 Excel 里看到的内容。适用场景是常规 .xlsx/.xls 表格;合并单元格、多级表头、超宽表需要单独处理;文件格式与引擎不匹配时会直接报错,不是数据问题。
Python读取Excel表格数据
「Python读取Excel表格数据」对应读取链路里的第二步:定位到具体工作表,并把表头行和数据区域切分正确,最终得到一个列名可读的 DataFrame。它前面是环境准备(pandas + 引擎),后面是清洗和分析。判断是不是卡在这一步,看三个位置:pd.ExcelFile(...).sheet_names 是否列出了你预期的表名;df.columns.tolist() 里是否出现 Unnamed: 0 这类占位列名;df.shape 的行数是否与 Excel 状态栏里选中数据区的行计数对得上。
直接把下面这段存成 probe.py 跑一遍,输出就是你要核对的事实:
import pandas as pd
book = pd.ExcelFile("订单.xlsx", engine="openpyxl")
print("工作表:", book.sheet_names)
df = book.parse("Sheet1", header=0, dtype=str)
print("shape:", df.shape)
print("columns:", df.columns.tolist())
print(df.head(5).to_string())
如果 columns 里出现 Unnamed,或 shape 的行数比 Excel 里少一行,通常说明表头上方还有一行标题、或者 header 填错了行号,而不是数据丢了。
Python读取Excel文件太慢
「Python读取Excel文件太慢」对应的不是同一个环节,它落在读取链路的第一步到第二步之间:打开文件、解析 XML、构建 DataFrame 这三段各自耗时多少。判断是不是它,不要凭感觉,用 time.perf_counter() 把打开和解析分开计时,同时看一眼文件体积(ls -lh 订单.xlsx)。如果文件只有几 MB 却要几十秒,通常是表里有大量格式、图片、合并单元格,或者用了 read_only 之外的默认加载方式。
import time, pandas as pd
t0 = time.perf_counter()
book = pd.ExcelFile("大表.xlsx", engine="openpyxl")
t1 = time.perf_counter()
df = book.parse(book.sheet_names[0], usecols="A:M")
t2 = time.perf_counter()
print(book.sheet_names)
print("打开耗时", round(t1 - t0, 2), "解析耗时", round(t2 - t1, 2), "行数", len(df))
能做的收敛动作是有限的:用 pd.ExcelFile 只打开一次再多次 parse 复用;用 usecols 限定列范围;用 nrows 先抽样确认识别无误再全量读。如果同一份数据要反复读,建议先转成 CSV 或 Parquet 存一次,后续都读转换后的文件——这属于绕开解析开销,不是把 Excel 读取本身变快。
读取Excel:先把能核对的事实摆清楚
先不急着改代码,把下面几项逐条打出来,写在同一个脚本里一起跑:

- 对象:文件绝对路径、文件大小、扩展名是
.xlsx还是.xls、工作表名列表。 - 环境:
python -c "import pandas, openpyxl; print(pandas.__version__, openpyxl.__version__)",以及pip show openpyxl里的 Location 行,确认装在了当前解释器里。 - 结构:
df.shape、df.columns.tolist()、df.dtypes、df.isna().sum()。 - 对照:在 Excel 里选中数据区,看状态栏的计数,与
len(df)加表头行比对。
这些输出都不带解释,但能直接决定方向:列名是 Unnamed 就去修 header;行数不一致就去查空行和合并单元格;dtypes 全是 object 就去查数字列里混入的文本或空格。这一步先不下结论,是因为很多“读不出来”最后发现是文件格式与引擎不匹配,改参数也无效。
读取Excel最容易搞错的一点
最常见的误解是把“代码没报错”当成“数据读对了”。read_excel 顺利返回一个 DataFrame,只能说明文件能被解析,不能说明表头行、合并单元格、空行已经被正确切分。分界线很明确:columns 是正常字段名,且 len(df) 与 Excel 里实际数据行数一致,才算读对;只要出现 Unnamed 或行数差一,就属于没读对。
一个能区分两种情况的检查动作:对同一个文件分别用 header=0 和 header=None 各读一次,打印 df.head(3)。如果 header=None 时第一行内容才是真正的字段名,说明表头上方还有标题行,应改为 header=1 或直接 skiprows。另一个高频误解是拿 openpyxl 去读 .xls——引擎和格式要对应,.xlsx 用 openpyxl,老式 .xls 需要另装对应引擎,不匹配时会直接抛 Excel file format cannot be determined 或 Missing optional dependency。
读取Excel:一个照着就能做完的做法
下面这条路径从建环境到校验,每步都写了应该看到什么。
- 建独立环境并安装:
python -m venv venv,然后source venv/bin/activate(Windows 为venv\Scripts\activate),再执行pip install pandas openpyxl。应看到Successfully installed,末尾带版本号。 - 确认解释器与包对齐:
pip show openpyxl的Location应指向当前 venv 目录,而不是系统 site-packages。 - 列出工作表:
python -c "import pandas as pd; print(pd.ExcelFile('订单.xlsx').sheet_names)"。应看到中括号里的表名列表,而不是报错。 - 按表名和范围读入:
df = pd.read_excel("订单.xlsx", sheet_name="Sheet1", header=0, usecols="A:M", dtype=str)。选dtype=str是为了先避开工号、订单号被识别成数字的问题,清洗阶段再转换。 - 三项校验:打印
df.shape、df.columns.tolist()、df.isna().sum()。应看到列名无Unnamed、行数与 Excel 状态栏计数一致。 - 落一份中间文件:
df.to_csv("订单.csv", index=False, encoding="utf-8-sig"),后续反复读取都走这个 CSV。应看到当前目录出现 csv 文件,且用 Excel 打开中文不乱码。
执行中可能撞到三种报错,按报错定位即可:FileNotFoundError 是路径问题,换成绝对路径;Missing optional dependency 'openpyxl' 是引擎没装进当前环境;ValueError: Excel file format cannot be determined 是扩展名与实际格式不符,用 file 订单.xlsx 看真实类型。版本号、引擎支持的格式这类会变的信息,以 pip show 的输出和 pandas 安装后 pd.read_excel.__doc__ 里的 engine 说明为准。