python 操作 Excel 的基本操作——模块化

因最近工作需要将数据写入excel,并设置格式,编写此Excel操作模块,以便未来还要用到。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
python复制代码# !/usr/bin/env python
# -*- coding: utf-8 -*-
"""
@Time : 2021/7/21 11:31
@Author : luoshixiang
@Email : luoshixiang@shsnc.com
@File : Parse_Excel.py
"""

import os
import openpyxl
from openpyxl.styles import PatternFill, Border, Side, Alignment, Protection, Font,colors
from openpyxl.drawing.image import Image
from openpyxl.chart import Series,LineChart,Reference

def create_excel(sheetname, filename):
# 创建一个workbook对象
wb = openpyxl.Workbook()
# 激活一个sheet
sheet = wb.active
# 为sheet设置表名sheetname
# sheet.title = 'Sheet1'
for i in range(len(sheetname)):
wb.create_sheet(sheetname[i])
ws = wb['Sheet']
wb.remove(ws)
wb.save(filename)

import openpyxl
def write_excel(title, sheet_name, data, filename):
# 创建一个workbook对象
wb = openpyxl.Workbook()
# 激活一个sheet
sheet = wb.active
# 为sheet设置一个表名sheetname
sheet.title = sheet_name
# 添加表头(不需要表头可以不用加)
for i in range(len(title)):
sheet.cell(row=1, column=i + 1, value=title[i])
# 添加表内容
for row_index, row_item in enumerate(data): # 获取索引和内容
for col_index, col_item in enumerate(row_item):
sheet.cell(row=row_index + 2, column=col_index + 1, value=col_item) # 写入
wb.save(filename)
return filename

class Parse_Excel(object):
"""解析excel文件"""
def __init__(self, filename, sheet_name = None):
try:
if os.path.exists(filename) == True:
# 获取绝对路径下的文件名称
self.filename = os.path.realpath(filename)
# 打开文件,获取excel文件的workbook(工作簿)对象
self.__wb = openpyxl.load_workbook(self.filename, data_only=True)
if sheet_name:
self.__sheet_name = sheet_name
else:
# 获取活跃表单
self.__ws = self.__wb.active # self.__ws的值与self.__wb[sheet_name]的值相同
# 获取活跃表名称
self.__sheet_name = self.__ws.title
else:
# 创建一个workbook对象
self.__wb = openpyxl.Workbook()
# 激活一个sheet
self.__ws = self.__wb.active
# 为sheet设置表名sheetname
if sheet_name:
self.__wb.create_sheet(sheet_name)
self.__sheet_name = sheet_name
# self.__wb.save(filename)
else:
self.__ws.title = 'Sheet1'
self.__ws = self.__wb['Sheet']
self.__wb.remove(self.__ws)
self.__wb.save(filename)
# 获取绝对路径下的文件名称
self.filename = os.path.realpath(filename)
except FileNotFoundError as e:
raise e
def save(self):
self.__wb.save(self.filename)

def create_sheets(self, sheet_name):
for i in range(len(sheet_name)):
self.__wb.create_sheet(sheet_name[i])

def remove_sheets(self, sheet_name):
for i in range(len(sheet_name)):
self.__wb.remove(sheet_name[i])

def get_max_row_num(self):
"""获取最大行号"""
sheet_name = self.__sheet_name
max_row_num = self.__wb[sheet_name].max_row
return max_row_num
def get_max_column_num(self):
"""获取最大列号"""
sheet_name = self.__sheet_name
max_column = self.__wb[sheet_name].max_column
return max_column
def get_row_value(self, row):
"""获取某一行的数据"""
sheet_name = self.__sheet_name
column_num = self.get_max_column_num()
row_value = []
if isinstance(row, int):
for column in range(1, column_num + 1):
values_row = self.__wb[sheet_name].cell(row, column).value
row_value.append(values_row)
# while None in values_row: # 去除列表中的None值和nall值
# values_row.remove(None)
return row_value
else:
raise TypeError('row must be type int')

def get_column_value(self, column):
"""获取某一列数据"""
sheet_name = self.__sheet_name
row_num = self.get_max_row_num()
column_value = []
if isinstance(column, int):
for row in range(1, row_num + 1):
values_column = self.__wb[sheet_name].cell(row, column).value
column_value.append(values_column)
# while None in column_value: # 去除列表中的None值和nall值
# column_value.remove(None)
return column_value
else:
raise TypeError('column must be type int')
def get_all_value(self):
"""获取指定表单的所有数据(除去表头)"""
sheet_name = self.__sheet_name
max_row_num = self.get_max_row_num()
max_column = self.get_max_column_num()
values = []
for row in range(2, max_row_num + 1):
value_list = []
for column in range(1, max_column + 1):
value = self.__wb[sheet_name].cell(row, column).value
value_list.append(value)
values.append(value_list)
return values

def get_all_value2(self):
"""获取指定表单的所有数据(包含表头)"""
sheet_name = self.__sheet_name
max_row_num = self.get_max_row_num()
max_column = self.get_max_column_num()
values = []
for row in range(1, max_row_num + 1):
value_list = []
for column in range(1, max_column + 1):
value = self.__wb[sheet_name].cell(row, column).value
value_list.append(value)
values.append(value_list)
return values
def get_excel_title(self):
"""获取sheet表头"""
sheet_name = self.__sheet_name
title_key = tuple(self.__wb[sheet_name].iter_rows(max_row=1, values_only=True))[0]
return title_key
def get_cell(self,location):
sheet_name = self.__sheet_name
cell_value = self.__wb[sheet_name][location].value
return cell_value
def get_cell_value(self,row,column):
sheet_name = self.__sheet_name
cell_value = self.__wb[sheet_name].cell(row,column).value
return cell_value

def my_border(self,t_border, b_border, l_border, r_border):
# 定义边框样式
border = Border(top=Side(border_style=t_border, color=colors.BLACK),
bottom=Side(border_style=b_border, color=colors.BLACK),
left=Side(border_style=l_border, color=colors.BLACK),
right=Side(border_style=r_border, color=colors.BLACK))
return border
# 初始化制定区域边框为所有框线
def format_border(self,s_column, s_index, e_column, e_index):
sheet_name = self.__sheet_name
for row in tuple(self.__wb[sheet_name][s_column + str(s_index):e_column + str(e_index)]):
for cell in row:
cell.border = self.my_border('thin', 'thin', 'thin', 'thin')

def set_solid_border(self,area_list):
"""给指定区域设置粗匣框线"""
# 调用方式:pe.set_solid_border([['A', 3, 'D', 5], ['A', 6, 'D', 7],['A', 3, 'A', 10], ['B', 3, 'C', 10]])
sheet_name = self.__sheet_name
for area in area_list:
s_column = area[0]
s_index = area[1]
e_column = area[2]
e_index = area[3]
#设置左粗框线
for cell in self.__wb[sheet_name][s_column][s_index - 1:e_index]:
cell.border = self.my_border(cell.border.top.style, cell.border.bottom.style,
'medium', cell.border.right.style)
# 设置右粗框线
for cell in self.__wb[sheet_name][e_column][s_index - 1:e_index]:
cell.border = self.my_border(cell.border.top.style, cell.border.bottom.style,
cell.border.left.style, 'medium')
# 设置上粗框线
for row in tuple(self.__wb[sheet_name][s_column + str(s_index):e_column + str(s_index)]):
for cell in row:
cell.border = self.my_border('medium', cell.border.bottom.style,
cell.border.left.style, cell.border.right.style)
# 设置下粗框线
for row in tuple(self.__wb[sheet_name][s_column + str(e_index):e_column + str(e_index)]):
for cell in row:
cell.border = self.my_border(cell.border.top.style, 'medium',
cell.border.left.style, cell.border.right.style)

def pattern_fill(self,rows,columns):
"""将单元格背景填充红色"""
sheet_name = self.__sheet_name
fill_set = PatternFill("solid", fgColor="00FF0000")
# fill_set = PatternFill("solid", fgColor="00FFFFFF")
font_set = Font(bold=True)
for i in range(2, columns ):
if int(self.__wb[sheet_name].cell(row = rows, column = i).value) >= 1:
self.__wb[sheet_name].cell(row = rows, column = i).fill = fill_set
self.__wb[sheet_name].cell(row=rows, column=i).font = font_set

def pattern_fill_cell(self, row, column):
# 将单元格标红
sheet_name = self.__sheet_name
fill_set = PatternFill("solid", fgColor="00FF0000")
font_set = Font(bold=True)
self.__wb[sheet_name].cell(row, column).border = self.my_border('thin', 'thin', 'thin', 'thin')
self.__wb[sheet_name].cell(row, column).fill = fill_set
self.__wb[sheet_name].cell(row, column).font = font_set

def set_border_cells(self,rows,columns):
"""将rows行加粗"""
sheet_name = self.__sheet_name
fill_set = PatternFill("solid", fgColor="00FF0000")
font_set = Font(bold=True)
for i in range(1, columns + 1):
self.__wb[sheet_name].cell(row=rows, column=i).font = font_set

def write_cell(self, row, column, value):
sheet_name = self.__sheet_name
if isinstance(row, int) and isinstance(column, int):
try:
cell_obj = self.__wb[sheet_name].cell(row, column)
cell_obj.value = value
except Exception as e:
raise e
else:
raise TypeError('row and column must be type int')

def write_sheet(self, data, title=None, value=None, bold=False):
sheet_name = self.__sheet_name
if title:
# 添加表头(不需要表头可以不用加)
self.write_sheet_title(title)
# 开始遍历数组
for row_index, row_item in enumerate(data): # 获取索引和内容
for col_index, col_item in enumerate(row_item):
# 写入
self.__wb[sheet_name].cell(row=row_index + 2, column=col_index + 1, value=col_item)


def write_sheet_from_column(self, data, column, title=None, value=None, bold=False):
sheet_name = self.__sheet_name
if title:
# 添加表头(不需要表头可以不用加)
self.write_sheet_title(title)
# 开始遍历数组
for row_index, row_item in enumerate(data): # 获取索引和内容
for col_index, col_item in enumerate(row_item):
# 写入
self.__wb[sheet_name].cell(row=row_index + 2, column=col_index +1 + column, value=col_item)


def write_sheet_from_positive_cell_row(self, data, row=2, column=1, title=None, value=None, bold=False):
sheet_name = self.__sheet_name
if title:
# 添加表头(不需要表头可以不用加)
self.write_sheet_title(title)
# 开始遍历数组
for row_index, row_item in enumerate(data): # 获取索引和内容
for col_index, col_item in enumerate(row_item):
# 写入
self.__wb[sheet_name].cell(row=row_index + row, column=col_index + column, value=col_item)

def write_sheet_from_positive_cell_col(self, data, row=2, column=1, title=None, value=None, bold=False):
sheet_name = self.__sheet_name
if title:
# 添加表头(不需要表头可以不用加)
self.write_sheet_title(title)
# 开始遍历数组
for col_index, row_item in enumerate(data): # 获取索引和内容
for row_index, col_item in enumerate(row_item):
# 写入
self.__wb[sheet_name].cell(row=row_index + row, column=col_index + column, value=col_item)


def write_sheet_title(self,sheet_title):
# 添加表头
sheet_name = self.__sheet_name
for i in range(len(sheet_title)):
self.__wb[sheet_name].cell(row=1, column=i + 1, value=sheet_title[i])

def write_row_data(self,rows, sheet_data):
# 追加一行数据
sheet_name = self.__sheet_name
for i in range(len(sheet_data)):
self.__wb[sheet_name].cell(row=rows + 1, column=i+1, value=sheet_data[i])

def write_column_data(self,columns, sheet_data):
# 向max_column右边追加一列数据,从第二行开始写
sheet_name = self.__sheet_name
for i in range(len(sheet_data)):
self.__wb[sheet_name].cell(row=i + 2, column=columns+1, value=sheet_data[i])

def write_column_data2(self,columns, sheet_data):
# 向max_column右边追加一列数据,从第一行开始写
sheet_name = self.__sheet_name
for i in range(len(sheet_data)):
self.__wb[sheet_name].cell(row=i + 1, column=columns+1, value=sheet_data[i])

def delete_row_v(self, rows, columns, values):
sheet_name = self.__sheet_name
for i in range(2, rows +1):
if self.__wb[sheet_name].cell(row = i, column = columns).value == values:
self.__wb[sheet_name].delete_rows(i, 1)

def delete_row(self, row):
sheet_name = self.__sheet_name
self.__wb[sheet_name].delete_rows(row, 1)

def delete_all_value(self,row=1):
sheet_name = self.__sheet_name
max_row = self.get_max_row_num()
self.__wb[sheet_name].delete_rows(row,max_row)
# for i in range(max_row+1):
# self.__wb[sheet_name].delete_rows(i)

def get_tail10_value(self, row_num , num):
"""获取后10行的数据"""
sheet_name = self.__sheet_name
column_num = self.get_max_column_num()
if isinstance(row_num, int):
if row_num < num:
for row in range(2, row_num + 1):
row_value = []
for column in range(1, column_num + 1):
values_row = self.__wb[sheet_name].cell(row, column).value
row_value.append(values_row)
print(row_value)
else:
for row in range(row_num - num, row_num + 1):
row_value = []
for column in range(1, column_num + 1):
values_row = self.__wb[sheet_name].cell(row, column).value
row_value.append(values_row)
print(row_value)
else:
raise TypeError('row must be type int')

def get_bf_value(self, row_num):
"""获取后10行的数据"""
sheet_name = self.__sheet_name
column_num = self.get_max_column_num()
if isinstance(row_num, int):
row_value = []
for row in range(row_num - 11, row_num + 1):
col_value = []
for column in range(1, column_num + 1):
value_col = self.__wb[sheet_name].cell(row, column).value
col_value.append(value_col)
row_value.append(col_value)
return row_value
else:
raise TypeError('row must be type int')

def get_bf_value2(self, row_num):
"""获取后10行的数据"""
sheet_name = self.__sheet_name
column_num = self.get_max_column_num()
if isinstance(row_num, int):
row_value = []
for row in range(row_num - 11, row_num + 1):
col_value = []
for column in range(1, column_num + 1):
value_col = self.__wb[sheet_name].cell(row, column).value
if type(value_col) == int:
value_col = "%.2f%%" % (value_col * 100)
col_value.append(value_col)
row_value.append(col_value)
return row_value
else:
raise TypeError('row must be type int')

def get_bf_value3(self,row_begin, row_end, col_begin, col_end):
"""获取后10行的数据"""
sheet_name = self.__sheet_name
# column_num = self.get_max_column_num()
if isinstance(row_end, int):
row_value = []
for row in range(row_begin, row_end + 1):
col_value = []
for column in range(col_begin, col_end + 1):
value_col = self.__wb[sheet_name].cell(row, column).value
if type(value_col) == float:
value_col = "%.2f%%" % (value_col * 100)
col_value.append(value_col)
row_value.append(col_value)
return row_value
else:
raise TypeError('row must be type int')

def set_percent(self,row,column,row2=None, column2=None):
# 将单元格格式设置为百分比显示
sheet_name = self.__sheet_name
fill_set = PatternFill("solid", fgColor="00FF0000")
font_set = Font(bold=True)
if not row2:
row2 = self.get_max_row_num()
if not column2:
column2 = self.get_max_column_num()
for i in range(row, row2 + 1):
for j in range(column, column2 +1):
self.__wb[sheet_name].cell(i, j).number_format = '0.00%'

def set_percent_column(self,column):
# 将单元格格式设置为百分比显示
sheet_name = self.__sheet_name
max_row =self.get_max_row_num()
for i in range(1,max_row + 1):
self.__wb[sheet_name].cell(i, column).number_format = '0.00%'

def sum_column(self,column):
# 对列中数字类型单元格进行求和,将结果写在列的最后一行
data = self.get_column_value(column)
sum = 0
for i in data:
if type(i) == int:
sum += i
return sum

def set_date_row(self,row):
# 将单元格格式设置为百分比显示
sheet_name = self.__sheet_name
# 设置字体
font_set = Font(name='宋体', color='000000', size=12, bold=True)
max_col =self.get_max_column_num()
for i in range(1,max_col + 1):
self.__wb[sheet_name].cell(row, i).font = font_set
self.__wb[sheet_name].cell(row, i).number_format = 'mm月dd日'

def merge_cells(self,loc1,loc2): # loc1示例:'A1'
# 合并单元格
sheet_name = self.__sheet_name
# 设置对齐方式,水平是右对齐,垂直是居中
align = Alignment(horizontal='center', vertical='center', wrap_text=True)
# 设置字体
font_set = Font(name='宋体', color='000000', size=11, bold=False)
self.__wb[sheet_name].merge_cells(loc1+":"+loc2)
# self.__wb[sheet_name].merge_cells(start_row=2, start_column=1, end_row=4, end_column=4) # 与上一条等价
self.__wb[sheet_name][loc1].alignment = align
self.__wb[sheet_name][loc1].font = font_set

def unmerge_cells(self,sr,sc,er,ec):
# 分割单元格
sheet_name = self.__sheet_name
# self.__wb[sheet_name].unmerge_cells('A2:D2')
# self.__wb[sheet_name].unmerge_cells(start_row=2, start_column=1, end_row=4, end_column=4) # 与上一条等价
self.__wb[sheet_name].unmerge_cells(start_row=sr, start_column=sc, end_row=er, end_column=ec)

def add_image(self,img_path,loc): # loc示例:'A1'
# 插入图像
sheet_name = self.__sheet_name
# 制作一个图片
img = Image(img_path)
# 在单元格旁边添加工作表和锚
self.__wb[sheet_name].add_image(img, loc)

def column_dimensions(self,col_name1,col_name2): # col_name1示例:'A'
# 折叠列
sheet_name = self.__sheet_name
self.__wb[sheet_name].column_dimensions.group(col_name1,col_name2, hidden=True)

def add_formula(self,loc,formula):
# 添加公式
sheet_name = self.__sheet_name
self.__wb[sheet_name][loc] = formula # ws["A1"] = "=SUM(1, 1)"


def add_line_chart(self,title, min_row, min_col, line_name, save_img, max_row=None, max_col=None):
sheet_name = self.__sheet_name
self.chart = LineChart()
self.chart.title = title # 图的标题
self.chart.style = 2 # 线条的style
self.chart.width = 17
self.chart.height = 6.5
# self.chart.y_axis.title = '次数' # y坐标的标题
# self.chart.x_axis.number_format = 'mm-dd' # 规定日期格式 这是月,年格式
# self.chart.x_axis.majorTimeUnit = "Months" # 规定日期间隔 注意days;Months大写
# self.chart.x_axis.title = "时间点" # x坐标的标题
if not max_row:
max_row = self.get_max_row_num()
if not max_col:
max_col = self.get_max_column_num()

for i in range(2,max_col+1):
# 选中要画图的数据列(Y轴)
data = Reference(self.__wb[sheet_name], min_col=i, min_row=min_row, max_col=i,
max_row=max_row) # 图像的数据 起始行、起始列、终止行、终止列
seriesObj = Series(data, title="'" + line_name[i - 2])
self.chart.append(seriesObj)
# self.chart.add_data(data, titles_from_data=True, from_rows=True)
# 指定X轴选取的数据列
dates = Reference(self.__wb[sheet_name], min_col=1, min_row=min_row, max_col=1, max_row=max_row)
self.chart.set_categories(dates)
self.__wb[sheet_name].add_chart(self.chart, save_img) # 将图表添加到 sheet中的:A1

其中有一部分内容:向excel中输入公式,仅适用于结论,不适用于中间处理过程,若excel公式处理结果还被调用的话,需要另想他法。

本文转载自: 掘金

开发者博客 – 和开发相关的 这里全都有

0%