如何使用 Python openpyxl 包操作 Excel 工作簿?openpyxl Workbook 对象介绍
本节并不包含 Microsoft Excel 文件的读取和写入,如果你想了解相关内容,可以查看如何使用 Python openpyxl 包读取和写入 Excel 文件一节。
此外,本节内容也不涉及与 Excel 样式,计算或图表相关的内容。
Python openpyxl 包中的 Excel 工作簿对象 Workbook
Pythonopenpyxl
包中的Workbook
类,对应了我们通常所说的 Excel 工作簿,使用Workbook
对象可以获取 Excel 工作簿的相关信息,或对其中的内容进行操作。
如果正确调用了openpyxl
包的load_workbook
函数,那么其返回值将是一个Workbook
对象。
使用 Python openpyxl 包的 Workbook 对象创建 Excel 工作簿
当你希望创建一个新的 Excel 工作簿时,就需要使用 Pythonopenpyxl
包的Workbook
类的构造器。
Workbook(write_only=False, iso_dates=False)
- write_only 参数
write_only
参数表示被创建的 Excel 工作簿是否是只写的,只写工作簿仅支持整行数据的写入,不支持对单个单元格的操作,默认为False
(不是只写的),如果设置为True
,那么仅能对Workbook
对象执行一次保存操作。- iso_dates 参数
iso_dates
参数对应的属性iso_dates
,被官方标记为尚未完成。
使用构造器创建的 Python openpyxl 包的 Workbook 对象可能不包含工作表 Sheet
在默认情况下,使用构造器创建的openpyxl
Workbook
对象将拥有一个名称为Sheet
的 Excel 工作表。当构造器参数write_only
为True
时,只写Workbook
对象不会包含任何工作表,如果在Workbook
对象执行保存操作时依然如此,那么openpyxl
将尝试为Workbook
对象添加一个 Excel 工作表。
from openpyxl import Workbook
# 创建一个新的工作簿,默认包含 Sheet 工作表
workbook = Workbook()
print(workbook['Sheet'])
# 只写工作簿不包含任何工作表
write_only_workbook = Workbook(True)
print(write_only_workbook.worksheets)
<Worksheet "Sheet">
[]
使用 Python openpyxl 包的 Workbook 对象获取和设置当前活动的 Excel 工作表
Pythonopenpyxl
包的Workbook
对象的active
属性,可用于获取或设置 Excel 工作簿当前活动的工作表,在获取当前活动的工作表时,active
属性的返回值可能是空值None
。
workbook.active
workbook.active = worksheet
- worksheet 值
worksheet
是需要设置为活动的Worksheet
对象或 Excel 工作表的索引(int
整数类型),0
表示第一个工作表,-1
表示倒数第一个工作表。
为 Python openpyxl 包的 Workbook 对象设置的当前活动 Excel 工作表需要存在且可见
如果将Worksheet
对象设置为当前活动的 Excel 工作表,那么Worksheet
对应的工作表应该存在于 Excel 工作簿中,并且是可见的,否则会抛出异常ValueError: Worksheet is not in the workbook
或ValueError: Only visible sheets can be made active
。如果通过工作表索引设置当前活动的 Excel 工作表,则不存在抛出异常的情况,但可能导致openpyxl
Workbook
对象的active
属性返回空值None
,因为索引指示的位置没有 Excel 工作表。
在 Microsoft Excel 文件School.xlsx
中,工作表ClassA
,ClassB
,ClassC
依次排列。
# 请将命令行跳转至 School.xlsx 所在的目录,然后运行此脚本文件
from openpyxl import load_workbook
workbook = load_workbook('School.xlsx')
print(f'当前活动 {workbook.active}')
# 将倒数第一个工作表设置为当前活动的工作表
workbook.active = -1
print(f'当前活动 {workbook.active}')
# 将 ClassB 设置为当前活动的工作表
workbook.active = workbook['ClassB']
print(f'当前活动 {workbook.active}')
# 没有索引为 100 的工作表
workbook.active = 100
print(f'当前活动 {workbook.active}')
当前活动 <Worksheet "ClassA">
当前活动 <Worksheet "ClassC">
当前活动 <Worksheet "ClassB">
当前活动 None
使用 Python openpyxl 包的 Workbook 对象获取 Excel 工作表
Pythonopenpyxl
包的Workbook
对象实现了__getitem__
方法,你可以方便的使用[]
运算符并传递工作表的名称(不支持传递工作表索引),来获取 Excel 工作簿中特定的工作表。如果指定的工作表在 Excel 工作簿中不存在,那么将导致异常KeyError: 'Worksheet … does not exist.'
。
如果需要通过索引或切片表达式,来获取工作簿中的某个或某些工作表,那么可以使用openpyxl
包的Workbook
对象的worksheets
属性,该属性返回一个包含所有工作表对象的 Python 列表。
workbook.worksheets[slice]
- slice 值
slice
为需要获取的某个 Excel 工作表的索引,或表示某些 Excel 工作表的切片表达式。
由于可以采用[]
运算符,因此openpyxl
已弃用Workbook
类的get_sheet_by_name
方法。
# 请将命令行跳转至 School.xlsx 所在的目录,然后运行此脚本文件
import openpyxl
workbook = openpyxl.load_workbook('School.xlsx')
# 获取工作表 ClassA
sheet = workbook['ClassA']
print(sheet)
# 获取第二个和其之后的所有工作表
sheets = workbook.worksheets[1:]
print(sheets)
<Worksheet "ClassA">
[<Worksheet "ClassB">, <Worksheet "ClassC">]
使用 Python openpyxl 包的 Workbook 对象创建 Excel 工作表
Pythonopenpyxl
包的Workbook
对象的create_sheet
方法,可用于为 Excel 工作簿创建新的 Excel 工作表,并将其插入到指定位置,原本位于该位置的工作表将向后移动,如果他存在的话。create_sheet
方法的返回值是新工作表对应的Worksheet
对象。
workbook.create_sheet(title=None, index=None)
- title 参数
title
参数为新 Excel 工作表的名称(标题),如果省略或设置为None
,则openpyxl
会将新工作表命名为Sheet
。需要指出,工作表的名称可能拥有一个数字后缀,用于确保其不与其他名称重复。- index 参数
index
参数为新 Excel 工作表在工作簿的插入位置,0
表示插入到当前第一个工作表之前,-1
表示插入到当前最后一个工作表之前(新的 Excel 工作表将位于倒数第二)。如果该参数被省略或设置为None
,则openpyxl
会将新工作表放置于末尾,如果该参数表示的插入位置不存在工作表,则新的 Excel 工作表会出现在开头,当index
参数为负数时,或出现在末尾,当index
参数为正数时。
由于被创建的Workbook
对象,默认拥有一个名称为Sheet
的 Excel 工作表,因此,在未指定名称的情况下,方法create_sheet
创建的新工作表将被命名为Sheet1
,Sheet2
,Sheet3
等。
import openpyxl
workbook = openpyxl.Workbook()
# 由于已经存在 Sheet,因此新工作表名称为 Sheet1,他将被放置在末尾
new_sheet1 = workbook.create_sheet()
print(f'新工作表名称 {new_sheet1.title}')
print(f'最后一个工作表的名称 {workbook.worksheets[-1].title}')
# 新工作表名称为 Sheet2,他将被放置在开头
workbook.create_sheet(index=0)
print(f'第一个工作表的名称 {workbook.worksheets[0].title}')
# 新工作表名称为 New,他将被放置在目前倒数第二个工作表 Sheet 之前
new = workbook.create_sheet('New', -2)
print(workbook.worksheets)
新工作表名称 Sheet1
最后一个工作表的名称 Sheet1
第一个工作表的名称 Sheet2
[<Worksheet "Sheet2">, <Worksheet "New">, <Worksheet "Sheet">, <Worksheet "Sheet1">]
使用 Python openpyxl 包的 Workbook 对象复制 Excel 工作表
Pythonopenpyxl
包的Workbook
对象的copy_worksheet
方法,可用于复制 Excel 工作簿中的 Excel 工作表,并将得到的工作表副本添加至 Excel 工作簿的末尾,副本的名称通常以Copy
结尾。copy_worksheet
方法的返回值是 Excel 工作表副本对应的Worksheet
对象。
workbook.copy_worksheet(from_worksheet)
- from_worksheet 参数
from_worksheet
参数为被复制的 Excel 工作表对应的Worksheet
对象。
Python openpyxl 包仅能复制 Workbook 对象自身拥有的 Excel 工作表
openpyxl
Workbook
对象的copy_worksheet
方法,仅能复制包含在Workbook
对象中的 Excel 工作表,尝试将其他 Excel 工作簿对象的工作表传递给参数from_worksheet
,会导致异常ValueError: Cannot copy between worksheets from different workbooks
。
# 请将命令行跳转至 School.xlsx 所在的目录,然后运行此脚本文件
import openpyxl
workbook = openpyxl.load_workbook('School.xlsx')
# 复制工作表 ClassA
workbook.copy_worksheet(workbook['ClassA'])
print(f'ClassA 副本的名称为 {workbook.worksheets[-1].title}')
# 尝试复制其他工作簿的工作表
newbook = openpyxl.Workbook()
# ERROR 无法复制自身不拥有的工作表
workbook.copy_worksheet(newbook['Sheet'])
ClassA 副本的名称为 ClassA Copy
…
ValueError: Cannot copy between worksheets from different workbooks
使用 Python openpyxl 包的 Workbook 对象移动 Excel 工作表
Pythonopenpyxl
包的Workbook
对象的move_sheet
方法,可用于移动 Excel 工作簿中的工作表,从而改变工作表之间的顺序。事实上,openpyxl
通过先删除后插入来完成工作表的移动,他会计算被移动的 Excel 工作表的插入位置,并将其放置在插入位置对应的工作表之前。
workbook.move_sheet(sheet, offset=0)
- sheet 参数
sheet
参数为需要移动的 Excel 工作表的名称或其对应的Worksheet
对象。- offset 参数
offset
参数为 Excel 工作表插入位置与原索引之间的偏移值,1
表示插入位置为原索引加1
,-1
表示插入位置为原索引减1
,使用0
的效果相当于不移动。如果插入位置最终为负数,那么移动的效果可能并非你的预期,比如,当 Excel 工作簿拥有多个工作表时,对索引为0
的第一个工作表使用-1
,他会被放置在倒数第二的位置,而不是倒数第一,这与使用create_sheet
方法所产生的效果类似。
在移动 Excel 工作表ClassA
之后,工作表ClassB
将位于开头,此时指定参数offset
为-1
,会使ClassB
被移动至倒数第二的位置,因为计算的插入位置为-1
,即倒数第一的ClassA
之前。
# 请将命令行跳转至 School.xlsx 所在的目录,然后运行此脚本文件
from openpyxl import open
workbook = open('School.xlsx')
print(workbook.worksheets)
# 工作表 ClassA 将位于末尾
workbook.move_sheet('ClassA', 100)
print(workbook.worksheets)
# 当前第一个工作表 ClassB 将被移动至倒数第二的位置
b = workbook['ClassB']
workbook.move_sheet(b, -1)
print(workbook.worksheets)
[<Worksheet "ClassA">, <Worksheet "ClassB">, <Worksheet "ClassC">]
[<Worksheet "ClassB">, <Worksheet "ClassC">, <Worksheet "ClassA">]
[<Worksheet "ClassC">, <Worksheet "ClassB">, <Worksheet "ClassA">]
使用 Python openpyxl 包的 Workbook 对象移除 Excel 工作表
使用 Pythonopenpyxl
包的Workbook
对象的remove
方法,或使用del
关键字和[]
运算符,并给出工作表的名称,可移除 Excel 工作簿中的工作表。
workbook.remove(worksheet)
del workbook[name]
- worksheet 参数
worksheet
参数为需要移除的 Excel 工作表对应的Worksheet
对象。- name 值
name
为需要移除的 Excel 工作表的名称。
openpyxl
已弃用Workbook
类的remove_sheet
方法。
# 请将命令行跳转至 School.xlsx 所在的目录,然后运行此脚本文件
from openpyxl import open
workbook = open('School.xlsx')
# 删除工作表 ClassA,ClassB
del workbook['ClassA']
workbook.remove(workbook['ClassB'])
print(workbook.worksheets)
[<Worksheet "ClassC">]
使用 Python openpyxl 包的 Workbook 对象获取 Excel 工作表的名称和索引
Pythonopenpyxl
包的Workbook
对象的sheetnames
属性,返回一个包含所有 Excel 工作表名称的 Python 列表。
workbook.sheetnames[slice]
- slice 值
slice
为需要获取名称的某个或某些 Excel 工作表的索引或切片表达式。
openpyxl
已弃用Workbook
类的get_sheet_names
方法。
Pythonopenpyxl
包的Workbook
对象的index
方法,可用于获取指定 Excel 工作表在工作簿中的索引,第一个工作表的索引为0
。
workbook.index(worksheet)
- worksheet 参数
worksheet
参数为需要获取索引的 Excel 工作表对应的Worksheet
对象。
openpyxl
已弃用Workbook
类的get_index
方法。
# 请将命令行跳转至 School.xlsx 所在的目录,然后运行此脚本文件
from openpyxl import load_workbook
workbook = load_workbook('School.xlsx')
# 获取工作表的名称和索引
print(f'第二个工作表的名称 {workbook.sheetnames[1]}')
print(f'工作表 ClassC 的索引 {workbook.index(workbook["ClassC"])}')
第二个工作表的名称 ClassB
工作表 ClassC 的索引 2
使用 Python openpyxl 包的 Workbook 对象获取 Excel 工作簿的日期系统
Pythonopenpyxl
包的Workbook
对象的excel_base_date
属性或epoch
属性,可用于获取 Excel 工作簿日期系统的开始日期。
workbook.excel_base_date
什么是 Excel 工作簿的日期系统?
每一个 Excel 工作簿都指定了自己的日期系统,不同的日期系统具有不同的开始日期,Excel 会将日期计算为相对于开始日期的偏移值,因此,同一日期在不同日期系统中存储的数据并不相同。
# 请将命令行跳转至 1904.xlsx 所在的目录,然后运行此脚本文件
from openpyxl import load_workbook
workbook = load_workbook('1904.xlsx')
# 获取工作簿的日期系统
print(workbook.excel_base_date)
1904-01-01 00:00:00
使用 Python openpyxl 包的 Workbook 对象判断 Excel 工作簿是否为模板
Pythonopenpyxl
包的Workbook
拥有类变量template
和实例变量is_template
,他们的值始终为True
,官方似乎没有阐明其具体作用,因此template
和is_template
不能用于判断 Excel 工作簿是否是一个模板,你需要使用Workbook
对象的mime_type
属性来完成此目标,该属性用来说明 Excel 工作簿的 MIME 类型,当其包含template
时,可将工作簿视为模板。
workbook.mime_type
# 请将命令行跳转至 Hello.xltx 所在的目录,然后运行此脚本文件
from openpyxl import load_workbook
workbook = load_workbook('Hello.xltx')
# 工作簿是否为模板?
print('template' in workbook.mime_type)
True
Python openpyxl 包的 Workbook 对象的其他特性
以下是与openpyxl
Workbook
对象相关,但不太重要的一些特性,这些特性可能并非从 Microsoft Excel 文件获取,只是由openpyxl
包给出了固定值。
- encoding 变量
Workbook
对象的encoding
变量用于表示 Excel 工作簿的编码,他由openpyxl
指定为'utf-8'
。- path 变量
Python
openpyxl
包所处理的 Excel 文件本身是一个压缩文件,Workbook
对象的path
变量表示其在压缩文件中的路径,他由openpyxl
指定为'/xl/workbook.xml'
。- vba_archive 变量
Workbook
对象的vba_archive
变量是一个ZipFile
对象,表示与 VBA 相关的压缩文件,该压缩文件包含在 Excel 文件中,通常的名称为vbaProject.bin
。- data_only,read_only,write_only 属性
Workbook
对象的data_only
,read_only
,write_only
属性是只读的,他们由读取 Excel 文件或创建openpyxl
Workbook
对象时给出的实参来决定,由于相关文章已经进行了讲解,这里不再累述。
源码
src/zh/openpyxl/workbooks·codebeatme/office-programming·GitHub