又到了一月一次的财务小姐姐不舒服的时候了(我说的是处理工资条)。她们又要开始忙起来了。
最近收到一个朋友的一个小问题,他不知道如何处理,想问问我有什么好的办法。
我首先就想到了用python来处理excel的这个,于是就上手写了一个小程序,如下。
1.需求:由于财务统计了一张所有员工的工资单,但是在发工资的时候,不仅要将钱给到员工手中,
还需要一张单人的工资条。但是这样就要复制好多个标题头,贴到每个人的工资条上面
(n个员工就要复制n次,repeat很多,很麻烦)。
如图:原图如下:
想要实现的效果图如下:这样就可以打印,撕下来做成一张张的工资条了
2.分析:选用python来操作,调用openplxy包。
为了保存原表的数据,应该先将原表的所有内容全部保存在字典里面;
然后新建一张表,根据要求将数据粘贴进去;
之后对数据的格式按照原表的样式重新弄一遍。
3,上代码:
from openpyxl import Workbook, load_workbook
from openpyxl.styles import fills,colors,NamedStyle,Font,Side,Border,PatternFill,Alignment,Protection
import openpyxl
import datetime
import sys
"""先用一个类来实现一些表格的操作"""
class ExcelUtils():
"""获取Excel表格内容"""
# def __init__(self,excelfilepath,sheet_name):
# print(excelfilepath, sheet_name)
# self.excelfilepath = excelfilepath # excelfilepath 为excel文件的完整路径
# self.sheet_name = sheet_name #sheet_name为excel表的sheet名称
# self.ws = self.getsheet() #python的类可以在初始化方法中调用类的其他方法
def __init__(self, excelfilepath):
print(excelfilepath)
self.excelfilepath = excelfilepath # excelfilepath 为excel文件的完整路径
self.ws = self.getsheet() # python的类可以在初始化方法中调用类的其他方法
def getsheet(self):
self.wb = openpyxl.load_workbook(self.excelfilepath, data_only=True) # 获取整个excel表对象
# ws = self.wb.active # 获取当前sheet对象
# self.sheet_name = sheet_name # sheet_name为excel表的sheet名称
sheet_names = self.wb.sheetnames
ws = self.wb[sheet_names[len(sheet_names) - 1]]
return ws
def get_row_count(self):
row_count =self.ws.max_row #获取当前sheet的最大行数
return row_count
def __get_cell_value(self,row_index, col_index):
cell_value = self.ws.cell(row_index,col_index).value
# 根据入参的值获取单元格的数据,两个下划线表示类的私有化方法
return cell_value
def get_colum_count(self):
colum_count =self.ws.max_column #获取当前sheet的最大列数
return colum_count
def get_merged_info(self):
"""
获取合并单元格的坐标范围,例如:“C1: D2”
"""
merged_info = self.ws.merged_cells
return merged_info
def get_merged_cell_value(self,row_index, col_index):
"""
既能获取普通单元格的数据又能获取合并单元格数据
row_index和col_index,最小行和最小列请传1
该方法的原理为将合并单元格的范围都视为获取合单元格左上角第一个普通单元格的值
"""
cell_value = None
mergedlist = self.get_merged_info()
for merged in mergedlist:
# 将获取到的单元格对象拆分为四个值
row_start, row_end, colum_start, colum_end = merged.min_row, merged.max_row, merged.min_col, merged.max_col
if row_index >= row_start and row_index <= row_end:
if col_index >= colum_start and col_index <= colum_end:
cell_value = self.__get_cell_value(row_start, colum_start)
break # 防止循环去进行判断出现值覆盖的情况。找到了想要的值,就不能再继续找了,必须直接跳出循环,返回出去
else:
cell_value = self.__get_cell_value(row_index, col_index)
else:
cell_value = self.__get_cell_value(row_index, col_index)
return cell_value # 返回的就是合并单元的值,为字符串类型
def get_first_row(self):
"""
获取第一行的数据
"""
columns = excelutils.ws.max_column #获取最大列数
rowdata = []
for i in range(1, columns + 1): # range函数的结束数字本身并不执行,所以需要+1
cellvalue = excelutils.ws.cell(row=1, column=i).value
rowdata.append(cellvalue)
return rowdata
def get_sheet_data_by_dict(self):
#将整个sheet列表除了第一行以外的内容全部作为字典的值进行储存
rowdata = self.get_first_row()
all_sheet_value_dict = []
for row in range(1, self.ws.max_row ):
valuedict = {}
for col in range(1, self.ws.max_column + 1):
valuedict[rowdata[col - 1]] = self.get_merged_cell_value(row + 1, col)
all_sheet_value_dict.append(valuedict)
return all_sheet_value_dict
def save_excle(self):
self.wb.save(self.excelfilepath)
# argv_str = sys.argv
# # print(argv_str)
# excel_name = argv_str[1]
excel_name = "乾元农业2020年9月基地工资表.xlsx"
aa = ExcelUtils(excel_name)
"""获取合并的单元格内容,保存在title_head里面"""
title_head = []
title_head.append(aa.get_merged_cell_value(1, 1))
title_head.append(aa.get_merged_cell_value(2, 1))
title_head.append(aa.get_merged_cell_value(3, 1))
title_head.append(aa.get_merged_cell_value(3, 2))
title_head.append(aa.get_merged_cell_value(3, 3))
title_head.append(aa.get_merged_cell_value(3, 34))
title_head.append(aa.get_merged_cell_value(3, 35))
for i in range(3, 5):
for j in range(4, 34):
title_head.append(aa.get_merged_cell_value(i, j))
print(title_head)
"""获取每个单元格的内容保存在num_list"""
num_list = []
for i in range(5, aa.get_row_count()):
for j in range(4, 34):
num_list.append(aa.get_merged_cell_value(i, j))
other_list = []
for i in range(5, aa.get_row_count()-1, 2):
other_list.append(aa.get_merged_cell_value(i, 1))
other_list.append(aa.get_merged_cell_value(i, 2))
other_list.append(aa.get_merged_cell_value(i, 3))
other_list.append(aa.get_merged_cell_value(i, 34))
other_list.append(aa.get_merged_cell_value(i, 35))
# # #保存写操作
a = datetime.datetime.now()
date_str = a.strftime('%Y%m%d%H%M%S')
ws2 = aa.wb.create_sheet("数据处理" + date_str, 0)
# 批量合并单元格
"""先找一个字体的模板"""
my_alignment = Alignment(
horizontal = 'general', # 水平:常规
vertical = 'bottom', # 垂直:底部对齐
text_rotation = 0, # 文本方向:0度
wrap_text = False, # 自动换行
shrink_to_fit = False, # 缩小字体填充
indent = 0 # 缩进0
)
index_other_data = 0
# font = Font('黑体', size=14, color=colors.BLACK, bold=False, italic=True, underline='double')
"""定义好大标题和小标题的字体样式"""
font = Font('黑体', size=14, color=colors.BLACK, bold=True)
font_head2 = Font('黑体', size=10, color=colors.BLACK, bold=True)
"""设置合并单元格并写入数据和更改字体样式"""
my_alignment1 = Alignment(horizontal='center', vertical='center', wrap_text = True)
for i in range(1, (aa.get_row_count()-5)//2*6, 6):
ws2.merge_cells(start_row=i, start_column=1, end_row=i, end_column=35)
ws2.cell(i, 1).alignment = my_alignment1
ws2.cell(i, 1).font = font
ws2.cell(i, 1).value = title_head[0]
ws2.merge_cells(start_row=i+1, start_column=1, end_row=i+1, end_column=35)
ws2.cell(i+1, 1).alignment = my_alignment1
ws2.cell(i+1, 1).font = font
ws2.cell(i+1, 1).value = title_head[1]
ws2.merge_cells(start_row=i + 2, start_column=1, end_row=i + 3, end_column=1)
ws2.cell(i+2, 1).alignment = my_alignment1
ws2.cell(i+2, 1).font = font_head2
ws2.cell(i+2, 1).value = title_head[2]
ws2.merge_cells(start_row=i + 2, start_column=2, end_row=i + 3, end_column=2)
ws2.cell(i+2, 2).alignment = my_alignment1
ws2.cell(i+2, 2).font = font_head2
ws2.cell(i+2, 2).value = title_head[3]
ws2.merge_cells(start_row=i + 2, start_column=3, end_row=i + 3, end_column=3)
ws2.cell(i+2, 3).alignment = my_alignment1
ws2.cell(i+2, 3).font = font_head2
ws2.cell(i+2, 3).value = title_head[4]
ws2.merge_cells(start_row=i + 2, start_column=34, end_row=i + 3, end_column=34)
ws2.cell(i+2, 34).alignment = my_alignment1
ws2.cell(i+2, 34).font = font_head2
ws2.cell(i+2, 34).value = title_head[5]
ws2.merge_cells(start_row=i + 2, start_column=35, end_row=i + 3, end_column=35)
ws2.cell(i+2, 35).alignment = my_alignment1
ws2.cell(i+2, 35).font = font_head2
ws2.cell(i+2, 35).value = title_head[6]
ws2.merge_cells(start_row=i + 4, start_column=1, end_row=i + 5, end_column=1)
ws2.cell(i+4, 1).alignment = my_alignment1
ws2.cell(i+4, 1).value = other_list[index_other_data]
ws2.merge_cells(start_row=i + 4, start_column=2, end_row=i + 5, end_column=2)
ws2.cell(i+4, 2).alignment = my_alignment1
ws2.cell(i+4, 2).value = other_list[index_other_data+1]
ws2.merge_cells(start_row=i + 4, start_column=3, end_row=i + 5, end_column=3)
ws2.cell(i+4, 3).alignment = my_alignment1
ws2.cell(i+4, 3).value = other_list[index_other_data+2]
ws2.merge_cells(start_row=i + 4, start_column=34, end_row=i + 5, end_column=34)
ws2.cell(i+4, 34).alignment = my_alignment1
ws2.cell(i+4, 34).value = other_list[index_other_data+3]
ws2.merge_cells(start_row=i + 4, start_column=35, end_row=i + 5, end_column=35)
ws2.cell(i+4, 35).alignment = my_alignment1
ws2.cell(i+4, 35).value = other_list[index_other_data+4]
index_other_data += 5
index_num_data = 0
"""写入单个单元格的数据并设置样式"""
for row in range(3, (aa.get_row_count()-5)//2*6, 6):
index_head_data = 7
for i in range(4, 34):
ws2.cell(row, i).alignment = Alignment(horizontal='center', vertical='center', wrap_text=True)
ws2.cell(row, i).value = title_head[index_head_data]
ws2.cell(row+1, i).alignment = Alignment(horizontal='center', vertical='center', wrap_text=True)
ws2.cell(row+1, i).value = title_head[index_head_data+30]
ws2.cell(row+2, i).alignment = Alignment(horizontal='center', vertical='center', wrap_text=True)
ws2.cell(row+2, i).value = num_list[index_num_data]
ws2.cell(row+3, i).alignment = Alignment(horizontal='center', vertical='center', wrap_text=True)
ws2.cell(row+3, i).value = num_list[index_num_data + 30]
index_head_data += 1
index_num_data += 1
index_num_data += 30
"""设置某些指定单元格的宽度"""
letter_A = chr(65)
ws2.column_dimensions[letter_A].width = 5
for i in range(3, 26):
letter = chr(i + 65)
ws2.column_dimensions[letter].width = 4
for i in range(0, 7):
letter_A = chr(65)
letter = chr(i + 65)
ws2.column_dimensions[letter_A+letter].width = 4
aa.save_excle()
print('完成!')
4,程序运行之后的效果图:多了一个sheet,也就是第一个
5.总结:新手刚学,CV的地方太多,有些地方还可以优化,由于时间关系,先就这样实现,后面有新的需求,
再一起优化一下~
对于有C++等编程基础的同学, 搞python上手还是挺快的,毕竟都是面向对象嘛。对象?这个程序中我只有一个对象,不合理。。。