import os
from openpyxl import load_workbook
from openpyxl.styles import PatternFill, Alignment, Side, Border
定义表头颜色样式为橙色
header_fill = PatternFill('solid', fgColor='FF7F24')
定义表中颜色样式为淡黄色
content_fill = PatternFill('solid', fgColor='FFFFE0')
定义表尾颜色样式为淡桔红色
bottom_fill = PatternFill('solid', fgColor='EE9572')
定义对齐样式横向居中、纵向居中
align = Alignment(horizontal='center', vertical='center')
定义边样式为细条
side = Side('thin')
定义表头边框样式,有底边和右边
header_border = Border(bottom=side, right=side)
定义表中、表尾边框样式,有左边
content_border = Border(left=side)
设置文件夹路径
path = './各部门利润表汇总_副本/'
返回当前目录下所有文件名
files = os.listdir(path)
循环文件名列表
for file in files:
# 拼接文件路径
file_path = path + file
# 打开工作簿
wb = load_workbook(file_path)
# 打开工作表
ws = wb.active
# 调整列宽
ws.column_dimensions['A'].width = 10
ws.column_dimensions['B'].width = 25
ws.column_dimensions['C'].width = 50
ws.column_dimensions['D'].width = 10
ws.column_dimensions['E'].width = 20
ws.column_dimensions['F'].width = 15
# 循环第一行单元格,调整表头样式
for cell in ws[1]:
# 设置单元格填充颜色
cell.fill = header_fill
# 设置单元格对齐方式
cell.alignment = align
# 设置单元格边框
cell.border = header_border
# 获取最后一行行号
row_num = ws.max_row
# 从第二行开始,循环到倒数第二行
for row in ws.iter_rows(min_row=2, max_row=(row_num-1)):
# 循环取出单元格,调整表中样式
for cell in row:
cell.fill = content_fill
cell.alignment = align
cell.border = content_border
# 循环最后一行单元格,调整表尾样式
for cell in ws[row_num]:
cell.fill = bottom_fill
cell.alignment = align
cell.border = content_border
# 保存
wb.save(file_path)
根据我们刚刚的一番对比分析,需要调整的格式有:表格的列宽、单元格的颜色、对齐方式和边框。
你可能会猜,是不是就要分成这四个功能块?
其实不然,因为Python中的openpyxl库整合了一些“修改单元格样式”的功能,设置起来很有规律,所以无需分为四个功能分别实现。
所谓整合,其实跟用Excel软件的工具栏处理非常类似,比如下面这个动图中展示的就是,选中单元格后,选择样式工具栏如“填充颜色”,再确认所需样式内容如“红色”,最后“点击”,样式修改就完成了。
难道说也可以用openpyxl库选择样式类别,确认样式值并执行修改,来完成样式设置?
确实是这样,而且只需:选择样式属性,定义该属性的样式值 , 赋值修改(具体各个)单元格的样式值。
因此对于所有单元格样式的修改可以分为两个功能块:“定义单元格样式” 和 “循环修改单元格”。
再加上对于表格的操作——“打开工作表”和“保存工作簿”,以及“调整(工作表)列宽”的功能,共有五个功能块。
- 设置Excel样式
3.1 打开工作表
既然我们之前已经复习过了如何打开一个工作簿和工作表,那就直接进入。如何打开文件夹下所有工作簿?
“各部门利润表汇总”文件夹中的52个工作簿——“事业01部.xlsx”、“事业02部.xlsx”等等,每次打开都要重复告诉load_workbook()函数它们的不同路径。
而工作簿的路径又有很强的规律性,都是文件夹路径 + 文件名。
那如果我们能用循环遍历取到不同的文件名,再一一拼接上前面的文件夹路径,问题就不大了。所以需要用到os.listdir()和for循环。
3.2 调整列宽
调整工作表的列宽,需要用到Sheet.column_dimensions['列位置'].width。
这条语句可以确定列位置,并用 width 属性,对该列的列宽进行修改。
比如说我想让第1列的列宽为20个单位,那么我就可以用 ws.column_dimensions['A'] 先确定找到第1列。
然后使用ws.column_dimensions['A'].width = 20进行赋值。
要注意这条语句中的三个要点:ws工作表变量、中括号中的列位置 和 等号后赋值的列宽。其中工作表变量可以任取,列位置用字符串类型的大写英文字母表示,列宽用数字类型的数据表示。
到这里,我们就完成了“调整列宽”功能块。接下来我们将会学习如何去定义和修改单元格的样式属性。
还记得吗?前面划分功能块时,我们类比Excel软件的设置方法,先确认样式工具栏并选择需要的样式,点击修改后,单元格的颜色才会真正的改变。使用openpyxl库操作也是一样的,要先定义好样式,再来修改单元格样式。
3.3 定义单元格样式
要想实现这个功能块,我们得根据任务要求去确定,要对单元格的哪些样式进行调整,以及该如何定义具体的样式。先来看一下代码:
首先第 3 行从openpyxl库的styles模块中,导入了4个表示各类别的样式对象。
1.PatternFill 对象表示填充,可以用于填充颜色。所以第 6、8、10 三行代码分别定义了3种颜色样式;
2.Alignment 对象表示对齐方式,所以第 13 行代码定义了1种对齐样式;
3.Border 对象表示边框,所以第 18、20 行代码分别定义了2种边框样式;
4.第16行代码Side对象是作为Border对象的参数值,它的作用是定义边样式。
from openpyxl.styles import PatternFill, Alignment, Side, Border
定义表头颜色样式为橙色
header_fill = PatternFill('solid', fgColor='FF7F24')
定义表中颜色样式为淡黄色
content_fill = PatternFill('solid', fgColor='FFFFE0')
定义表尾颜色样式为淡桔红色
bottom_fill = PatternFill('solid', fgColor='EE9572')
定义对齐样式横向居中、纵向居中
align = Alignment(horizontal='center', vertical='center')
定义边样式为细条
side = Side('thin')
定义表头边框样式,有底边和右边
header_border = Border(bottom=side, right=side)
定义表中、表尾边框样式,有左边
content_border = Border(left=side)
定义好样式之后,就可以去修改属性值,改变单元格的样式了。
看第 46-51 行中的代码,是在设置表头单元格的样式属性。
for cell in ws[1]:
# 设置单元格填充颜色
cell.fill = header_fill
# 设置单元格对齐方式
cell.alignment = align
# 设置单元格边框
cell.border = header_borde
看第 46-51 行中的代码,是在设置表头单元格的样式属性。
比如将第6行定义好的,颜色样式header_fill赋值给该单元格的填充属性fill,即可完成填充样式的设置。
这说明,我们在设置具体单元格的样式属性时,用的是赋值修改的方法。
这种先定义样式再赋值执行,与Excel软件中选好样式工具栏中的具体样式再“点击”修改,倒挺相近的。
因此,我们在“定义单元格样式”功能块中需要学习的:
1.是单元格的样式属性(样式工具栏);
2.是如何定义各样式属性的具体值(工具栏中具体样式);
到下一个功能再进行实际修改(点击)。
单元格有很多的属性,比如上一节课学过的Cell.value属性,表示单元格的值。而关于单元格的样式属性,今天我们会了解到三个,基本可以对应Excel中这三处工具栏:
1.边框样式由Cell.border属性表示,2.颜色填充由Cell.fill属性表示,3.对齐方式由Cell.alignment属性表示。
以上就是本次需要用到的样式属性,接下来我们来看里面具体的样式如何定义,就能知道这些样式属性分别能存储什么样的样式效果了。
单元格样式的定义
Excel中的边框样式非常丰富,有上下左右不同位置,还有边框的线条形状粗细,这些效果在openpyxl中可以实现吗?
当然可以,边框样式由Border对象来定义,线条由Side对象定义,想要什么样的都可以。因为通过对类的不同参数设置不同的参数值,就可以定义出各种不同的样式效果。
例如,如何定义一个细线条的下边框样式?
先定义个细线条的边框线 —— side = Side('thin'),thin表示细的。再来定义下边为细线条的边框样式boder1 —— boder1 = Border(bottom=side),bottom表示底部。所以底部边框是细线条的样式就定义好了。
是不是并不像想象的那么难?我们直接来看“边框”、“填充”、“对齐”等不同属性该如何定义吧。
根据上面的图片,我们会发现:填充样式、对齐样式,与边框样式一样,都是由特定的类,实例化得到的。
而具体的样式效果则由参数来确定。比如填充样式PatternFill类的fgColor参数表示前景颜色,如果将颜色的RGB值传给该参数,就可以填充为该颜色。(填充一种颜色时,设置前景色即可。)
同理,对齐方式Alignment类的horizontal参数表示水平方向上的对齐,如果参数值是'center'则表示水平居中。
那么来做一道题,具体尝试一下如何定义出不同的样式。
从openpyxl库styles模块中导入四个类
from openpyxl.styles import PatternFill, Alignment, Side, Border
定义表头填充样式,颜色为橙色,纯色填充
header_fill = PatternFill('solid', fgColor='FF7F24')
定义表中填充样式,颜色为淡黄色,纯色填充
content_fill = PatternFill('solid', fgColor='FFFFE0')
定义表尾填充样式,颜色为淡桔红色,纯色填充
bottom_fill = PatternFill('solid', fgColor='EE9572')
定义对齐样式横向居中、纵向居中
align = Alignment(horizontal='center', vertical='center')
定义边样式为细边框
side = Side('thin')
定义表头边框样式,有底部和右侧细边框
header_border = Border(bottom=side, right=side)
定义表中、表尾边框样式,有左侧细边框
content_border = Border(left=side)
3.4 循环修改单元格
由于表头、表中、表尾的样式分别不同,所以我们把这个功能块分成这3部分,分别去完成。先来看如何取出表头的单元格,并进行样式修改。
修改“表头”的单元格样式
先来观察一下第一行,表头的单元格
表头是第一行的单元格,如果要取出这一行很简单,用ws[1]就可以了。然后就可以用for cell in ws[1]取出每个单元格,再来对单元格的样式属性进行修改。
不过,你可能会问,第一行的表格已经合并了,它不就是一个单元格吗?为什么还要循环修改呢?
这是因为,对于这个大的合并单元格来说,它其实不是单元格(Cell)对象,而是合并单元格(MergedCell)对象,合并单元格对象没有这些样式的属性。所以不能直接对这个大的单元格进行样式修改。
接下来我们来结合上面定义好的单元格样式,看看如何修改表头单元格的样式
导入模块
from openpyxl import load_workbook
from openpyxl.styles import PatternFill, Alignment, Side, Border
定义表头颜色样式为橙色
header_fill = PatternFill('solid', fgColor='FF7F24')
定义表中颜色样式为淡黄色
content_fill = PatternFill('solid', fgColor='FFFFE0')
定义表尾颜色样式为淡桔红色
bottom_fill = PatternFill('solid', fgColor='EE9572')
定义对齐样式横向居中、纵向居中
align = Alignment(horizontal='center', vertical='center')
定义边样式为细条
side = Side('thin')
定义表头边框样式,有底边和右边
header_border = Border(bottom=side, right=side)
定义表中、表尾边框样式,有左边
content_border = Border(left=side)
打开工作表
file_path = './material/事业01部_副本.xlsx'
wb = load_workbook(file_path)
ws = wb.active
循环第一行单元格,调整表头样式
for cell in
ws[1]
:
# 修改单元格填充颜色
cell.fill =
header_fill
# 修改单元格对齐方式
cell.alignment =
align
# 修改单元格边框
cell.border =
header_border
现在我们已经实现对一个工作表中表头单元格样式的修改啦,赶紧继续来看表中单元格修改吧。
修改“表中”的单元格样式
来观察一下表中的单元格:
表中”是中间2-9行的单元格,如果要取出这一行很简单,但是怎么取出这一个区域中的行,继而取出单元格呢?
不知道你还记不记得,我们之前接触过一个方法,可以取出工作表中一定范围的数据。
那就是工作表Sheet的iter_rows()
方法,它有两个参数max_row和min_row,可以指定所取数据的行数范围(从min_row行取到max_row行为止)。
我们来体验一下,运行下面代码,查看9-10行代码的运行结果:
这里为了打印数值,还用到了一个之前也见过的参数设置——values_only=True,意思就是说只取数值。
待会儿我们遍历取出行,是要进行样式修改的,不能只取数值,所以使用iter_rows(min_row,max_row),此时values_only默认为False。
经过这个练习你是否记起了Sheet.iter_rows()的使用呢?遗忘没关系,先记住这个功能,课后多去实操几遍代码,熟了就能生巧。
有了Sheet.iter_rows(),我们就可以根据其最大行参数值和最小行参数值,确定需要修改的范围了。
其实还有另一个问题,你可能忽略了。那就是:刚刚只是对“事业01部”进行处理,所以可以知道最大行参数是取到第9行,如果是其他工作表,表中区域可能就不是从第2-第9行了,而是从第2行到倒数第2行。
那应该如何取出不同工作表的倒数第二行的行号呢?这时候我们需要一个新知识:Sheet.max_row。
max_row是工作表Sheet的一个属性,返回的属性值是一个整数。这个整数值代表了工作表的最大行数。如果工作表共有9行,那Sheet.max_row 返回的就是整数9。
取出“表中”的各行,并打印
for row in ws.iter_rows(min_row=2, max_row = ws.max_row - 1):
print(row)