以往我们处理 Excel 文件,只能手动打开 Excel 文件进行操作。如果碰到大量且重复性高的任务,一个个编辑文件就特别费时费力。这时我们可以借助 Python 读取和写入 Excel 文件的库 来进行文件的批量以及自动化处理。Python 提供了好几个能够操作 Excel 的库。本篇文章选择 Openpyxl 库作为教程。
考虑到有的朋友可能对 Excel 不太熟悉,我先在开头简单回顾一下 Excel 的基础概念:
-
层级关系工作簿(Workbook) ├── 工作表(Worksheet) │ ├── 单元格(Cell) │ ├── 单元格(Cell) │ └── ... ├── 工作表(Worksheet) └── ...一个工作簿包含多个工作表,每个工作表又由无数个单元格组成,单元格是 Excel 最小的数据存储单位
-
工作簿(Workbook)工作簿是 Excel 官方的叫法,它其实就是一个 Excel 文件,通常以 .xlsx 或 .xls 为扩展名
文件扩展名:
.xls ------ 普通 Excel 工作簿(Excel 早期版本:1997--2003) .xlsx ------ 普通 Excel 工作簿(Excel 2007 及之后版本) .xlsm ------ 带宏的工作簿 .xlsb ------ 二进制的工作簿创建工作簿的时候会自动生成 1 个工作表
-
工作表(Worksheet)工作表是工作簿内部的一张张独立表格。工作表的名称默认为"Sheet1"、"Sheet2"、"Sheet3" 依次递增,也可自行修改
工作表用于分类存放数据。例如一个名为"2026年财务报表"的工作簿,可以包含"1月"、"2月"等多个工作表
每个工作表是由行(Rows:从 1 开始编号,如 1, 2, 3...)和列(Columns:用字母表示A, B, C...)组成
-
单元格(Cell)单元格就是工作表上的一个个小格子。它是存储数据的最小单位,用来输入文本(字符串),数值(数字),日期 / 时间,公式(以 = 开头)
每个单元格都有唯一的地址标识,由「列标(字母) + 行号(数字)」组成。例如 A 列和第 1 行交叉的单元格,地址为 A1;C 列和第 5 行交叉的单元格,地址为 C5
当你点击某个格子,它周围会出现粗黑边框,此时它就是"活动单元格",你可以直接输入数据
Excel 工作界面:

PS:Openpyxl 的官方文档真是乱糟糟的,连一个目录总览都没有,全靠上一页下一页的挨个翻阅,翻了半天也看不到头,简直无力吐槽
PS:切换全屏:Ctrl+Shift+F1,再次按取消全屏
2. 安装
我使用 uv 作为 python 包管理工具。为了节省文章篇幅,安装 uv、使用 uv 安装 python 以及创建项目、创建虚拟环境等步骤略过。不会 uv 的同学可以看我的另一篇文章:
📝 《Python 入门(一)- 用 UV 管理 Python》:juejin.cn/post/760585...
安装 openpyxl 库
uv add openpyxl

安装后会在 pyproject.toml 文件写入 openpyxl 依赖

以及在 uv.lock 文件锁定 openpyxl 包的版本

3. 工作簿(Excel 文件)
3.1 工作簿创建
Workbook() 实例化的时候会自动创建一个工作表,并自动生成默认表名"Sheet"
Workbook.save() 方法将工作簿保存到磁盘上的文件中。如果文件不存在将创建文件,如果文件存在则进行内容覆盖
注意!覆盖 Excel 内容的时候,需要将当前打开的 Excel 文件关闭才能执行代码,否则 Excel 文件被占用,执行 Workbook.save() 方法会报错
from openpyxl import Workbook wb = Workbook() # 实例化 excel 工作簿对象 print("wb:", wb) wb.save("sample.xlsx") # 保存 excel print("创建成功!")

成功创建工作簿,并默认创建了一个名为 "Sheet" 的工作表

也可以指定路径创建,我这里将创建的 excel 文件放在 D 盘的 xlsx 文件夹下面
from openpyxl import Workbook wb = Workbook() # 实例化 excel 工作簿对象 print("wb:", wb) wb.save("D:\\xlsx\\sample.xlsx") # 保存 excel print("创建成功!")
注意!路径(xlsx 文件夹)需要存在,否则会报错


3.2 工作簿加载
注意,Openpyxl 不兼容旧版本的 Excel(Office2003 的 xls 格式)!旧版本可以用 xlrd 库进行 Excel 文件的读取,并且 xlrd 库要指定 1.2.0 版本才能同时支持新旧 Excel 版本;或者将旧版本的 xsl 转换为 xlsx 格式(推荐)
我不想为了兼容旧版本的 Excel 去多学一个库,所以我还是选择用 Openpyxl 库加载 Excel 文件
使用 load_workbook() 函数打开现有的 Excel 文件
from openpyxl import load_workbook wb = load_workbook(filename="sample.xlsx") # 获取所有工作表名称 print(wb.sheetnames)

打印出工作表的名称证明加载成功
3.3 工作簿删除
使用 os 库的 remove() 方法删除工作簿
import os os.remove("sample.xlsx") print("工作簿删除成功!")

也可以使用 os 库的 path.exists() 方法加一个判断提升代码健壮性:如果文件存在才删除,否则提示不存在
import os # 删除工作簿文件 file_path = "sample.xlsx" if os.path.exists(file_path): os.remove(file_path) print(f"已删除文件: {file_path}") else: print("文件不存在")
3.4 合并工作薄
我们可以将多个结构相同的 Excel 工作薄合并为一个
具体操作:略
3.5 拆分工作薄
我们也可以将结构相同的 Excel 工作薄拆分为多个
具体操作:略
4. 工作表
4.1 修改工作表的名称
Workbook() 实例化的时候会自动创建一个工作表,并自动生成默认表名。可以使用 Workbook.title 属性更改工作表的名称
from openpyxl import Workbook wb = Workbook() # 实例化 excel 工作簿对象 ws = wb.active # 获取当前活跃的工作表 ws.title = "工资表" # 修改当前工作表的名称 wb.save("sample.xlsx") # 保存 excel print("创建成功!")

表名被成功修改为"工资表"

4.2 创建新的工作表
create_sheet() 函数共有两个参数:
title(表名):若不指定工作表的名称,将按顺序递增自动生成(Sheet、Sheet1、Sheet2、...);如果表名重复了,它会自动加上数字1,2,3依此类推
index(索引值):正数从 0 开始从前往后生成工作表,负数从 -1 开始从后往前生成工作表,索引不指定时追加到最右侧
from openpyxl import Workbook wb = Workbook() # 实例化 excel 工作簿对象 ws2 = wb.create_sheet("天", 0) # 正数索引:从0开始,指定插入位置 ws2 = wb.create_sheet("青", 1) ws2 = wb.create_sheet("色", 2) ws2 = wb.create_sheet("等", 3) ws2 = wb.create_sheet("烟", 4) ws2 = wb.create_sheet("等", -1) # 负数索引:从末尾开始计数 ws2 = wb.create_sheet("在", -2) ws2 = wb.create_sheet("我", -3) ws2 = wb.create_sheet("而", -4) ws2 = wb.create_sheet("雨", -5) wb.save("sample.xlsx") # 保存 excel print("创建成功!")
我们按照歌词 "天青色等烟雨而我在等" 的顺序创建工作表

表名重复了,有两个等,所以第二个等被自动加上了数字1
默认创建的 Sheet 因为没加索引,所以默认排在最后

现在我们加上一行 ws1 = wb.create_sheet("你") 代码,索引为空将表插入到末尾
from openpyxl import Workbook wb = Workbook() # 实例化 excel 工作簿对象 ws1 = wb.create_sheet("你") # 索引为空:插入到末尾 ws2 = wb.create_sheet("天", 0) # 正数索引:从0开始,指定插入位置 ws2 = wb.create_sheet("青", 1) ws2 = wb.create_sheet("色", 2) ws2 = wb.create_sheet("等", 3) ws2 = wb.create_sheet("烟", 4) ws2 = wb.create_sheet("等", -1) # 负数索引:从末尾开始计数 ws2 = wb.create_sheet("在", -2) ws2 = wb.create_sheet("我", -3) ws2 = wb.create_sheet("而", -4) ws2 = wb.create_sheet("雨", -5) wb.save("sample.xlsx") # 保存 excel print("创建成功!")

注意看!神奇的事情发生了
表名 你,索引为空所以插入到末尾,这个很好理解
但是默认创建的 Sheet 跑到了中间,这又是咋回事?
我的理解是插入到末尾已经被表名 你 给占用了,所以默认创建的 Sheet 只能放在不属于这些带有索引下标的位置-也就是中间
所以大家创建多个表的时候,建议每个表都指定下标索引,避免排序混乱

4.3 查看所有工作表的名称
Workbook.sheetname() 函数查看工作簿中所有工作表的名称
在前面的 3.2 工作簿加载 章节已经用过此方法了,不再赘述
4.4 移动工作表(下标)
move_sheet(title, n) 函数移动工作表的下标,对其进行重新排序,参数如下:
title:Sheet 名称
n:负数表示向左移动,正数表示向右移动,数字表示移动几个位置
from openpyxl import load_workbook wb = load_workbook(filename="sample.xlsx") print(wb.sheetnames) # 获取所有工作表名称 wb.move_sheet("Sheet", 1) # -1 负数表示向左移动,正数表示向右移动,数字表示移动几个位置 print(wb.sheetnames) # 获取所有工作表名称

加载刚才创建的工作簿,然后将默认创建的 Sheet 向右移动了一个位置
需要保存 excel 的话,在最后调用 wb.save("sample.xlsx") 函数即可
4.5 复制工作表
Workbook.copy_worksheet(sheet):在当前工作簿复制指定的工作表并返回复制后的工作表对象
from openpyxl import Workbook wb = Workbook() # 实例化 excel 工作簿对象 ws = wb.active # 获取当前活跃的工作表 ws.title = "工资表" # 修改当前工作表的名称 new_worksheet = wb.copy_worksheet(ws) # 复制工作表 wb.save("sample.xlsx") # 保存 excel print("创建成功!")


不指定复制指定的工作表的名字的话,默认会在表名后加上 Copy
如果想指定名字的话加上 new_worksheet.title = "复制的工资表" 这句代码即可
4.6 删除工作表
del wb['SheetName']:在当前工作簿中删除指定的工作表
wb 是已加载的工作簿对象
SheetName 是想要删除的表名
from openpyxl import load_workbook wb = load_workbook(filename="sample.xlsx") print(wb.sheetnames) # 获取所有工作表名称 del wb["工资表 Copy"] # 删除工作表 print(wb.sheetnames) # 获取所有工作表名称

加载刚才创建的工作簿,然后将名为 "工资表 Copy" 的工作表删除
需要保存 excel 的话,在最后调用 wb.save("sample.xlsx") 函数即可
注意:旧的 remove_sheet() 删除工作表方法已被废弃
5. 单元格
5.1 单元格的内容写入
5.1.1 通过工作表的键
通过工作表的键填写单元格内容
from openpyxl import Workbook wb = Workbook() # 实例化 excel 工作簿对象 ws = wb.active # 获取当前活跃的工作表 ws.title = "工资表" # 修改当前工作表的名称 ws["A1"] = "姓名" # 给单元格填写值(通过工作表的键) wb.save("sample.xlsx") # 保存 excel print("创建成功!")


也可以加上 .value
# 给单元格填写值(通过工作表的键) ws["A1"].value = "工资表"
通过工作表的键获取单元格内容
print(ws["A1"].value)