经常看到身边的同事(包括自己)在弄Excel表格的时候,各种复制粘贴非常麻烦,尤其是每天做一样的工作,重复枯燥费时间,于是打算写个小脚本自动更新Excel表格。
image.png我们以这个表格为例,给大家看下表格长啥样儿,我们要更新的列是日期-字段9里面的数据,其中最后两列是套公式自动计算的。
我们这里主要使用pandas和openpyxl这两个库进行操作。
思路首先表格中肯定会存在制作好的公式,只要填入数据就能够自动刷新,那么我们需要的是利用Python来处理我们需要自行填充的部分
逐行更新问题:我们需要获取到当前表格的最大行,但是如果直接获取的话会存在一定的问题,如果表格这行的部分单元格有数据的话,Python会认为这一行就不是空行了,会导致数据错乱,因此我们的解决办法是用pandas去获取某列的行数,再此基础上增加一行,以达到自增的目的
那么思路有了就开始写代码吧
首先导包:from openpyxl import load_workbook # 读取Excel文件
from datetime import date, timedelta # 时间处理
import pandas as pd # 读取文件
import os # 操作本地文件
import logging # 打日志
然后新建个类,初始方法,两个方法,初始方法主要就是一些基本的配置参数、时间啊、文件名、文件路径之类的。第一个方法是获取当前表格某列的最大行数,在此基础上自增行数。第二个方法就是写入数据了。 class Writing_to_excel():
def __init__(self):
"""
基本参数配置:时间参数、文件路径、源文件名、临时文件名、工作表名、字段名
"""
self.data_ytd = (date.today() + timedelta(days=-1)).strftime("%Y/%m/%d")
self.filepath = '/Users/jason/Desktop/'
self.filename = 'test_data.xlsx'
self.filename_replace = 'tmp_test_data.xlsx'
self.sheet_name = '汇总'
self.column_name = '日期'第一个方法主要是利用pandas获取日期这列最大行数,看我的表格,最后两列是有数据的,如果直接用dataframe.shape[0]去获取的话,会把这列的NaT值也算作行数,所以我们要做一下dropna处理,这样我们就能获取到一个自增的行数了。
另外有个问题,如果源文件直接被pandas打开的话,数据会被清除格式,导致公式失效,所以我们要用os.system拷贝一个副本给我们操作,获取完行数之后删掉副本。def get_next_row(self):
"""
拷贝出新文件,获取行号
防止破坏源文件
:return: next_row
"""
os.system(f'cp {self.filepath}{self.filename} {self.filepath}{self.filename_replace}')
pd_data = pd.read_excel(f'{self.filepath}{self.filename_replace}', sheet_name=self.sheet_name)
col1 = pd_data[[self.column_name]].dropna()
_maxrow = col1.shape[0]
next_row = _maxrow + 2
pd_data.to_excel(f'{self.filepath}{self.filename_replace}', sheet_name=self.sheet_name)
os.system(f'rm {self.filepath}{self.filename_replace}')
self.next_row = next_row
return
接下来就是填入数据的方法:def write_data_to_excel(self):
"""
写入数据
:return:
"""
wb = load_workbook(f'{self.filepath}{self.filename}')
stotal = wb['汇总']
stotal[f'A{self.next_row}'] = self.data_ytd
stotal[f'B{self.next_row}'] = 77
stotal[f'C{self.next_row}'] = 77
stotal[f'D{self.next_row}'] = 77
stotal[f'E{self.next_row}'] = 77
stotal[f'F{self.next_row}'] = 77
stotal[f'G{self.next_row}'] = 77
stotal[f'H{self.next_row}'] = 77
stotal[f'I{self.next_row}'] = 77
stotal[f'J{self.next_row}'] = 77
wb.save(f'{self.filepath}{self.filename}')
用我们动态获取到的最大行数,来填入每个单元格的数据,这个就比较体力活了,暂时没想到更好的方法。最后save文件
最后,运行脚本if __name__ == '__main__':
try:
wte = Writing_to_excel()
wte.get_next_row()
wte.write_data_to_excel()
logging.info(f"{wte.filename} 文件数据操作完成")
print(f"{wte.filename} 文件数据操作完成")
except Exception as e:
logging.error(f"{wte.filename}操作失败!原因:{e}")
print(e)
细心的同学可以发现,我做了个简单的日志,方便查看报错的情况。
上运行结果:
image.png
最后,完整代码如下:from openpyxl import load_workbook
from datetime import date, timedelta
import pandas as pd
import os
import logging
LOG_FORMAT = "%(asctime)s %(name)s %(levelname)s %(pathname)s %(message)s "
DATE_FORMAT = '%Y-%m-%d %H:%M:%S'
logging.basicConfig(level=logging.DEBUG, format=LOG_FORMAT, datefmt=DATE_FORMAT, filename="excel_operate.log")
class Writing_to_excel():
def __init__(self):
"""
基本参数配置:时间参数、文件路径、源文件名、临时文件名、工作表名、字段名
"""
self.data_ytd = (date.today() + timedelta(days=-1)).strftime("%Y/%m/%d")
self.filepath = '/Users/jason/Desktop/'
self.filename = 'test_data.xlsx'
self.filename_replace = 'tmp_test_data.xlsx'
self.sheet_name = '汇总'
self.column_name = '日期'
def get_next_row(self):
"""
拷贝出新文件,获取行号
防止破坏源文件
:return: next_row
"""
os.system(f'cp {self.filepath}{self.filename} {self.filepath}{self.filename_replace}')
pd_data = pd.read_excel(f'{self.filepath}{self.filename_replace}', sheet_name=self.sheet_name)
col1 = pd_data[[self.column_name]].dropna()
_maxrow = col1.shape[0]
next_row = _maxrow + 2
pd_data.to_excel(f'{self.filepath}{self.filename_replace}', sheet_name=self.sheet_name)
os.system(f'rm {self.filepath}{self.filename_replace}')
self.next_row = next_row
return
def write_data_to_excel(self):
"""
写入数据
:return:
"""
wb = load_workbook(f'{self.filepath}{self.filename}')
stotal = wb[self.sheet_name]
stotal[f'A{self.next_row}'] = self.data_ytd
stotal[f'B{self.next_row}'] = 77
stotal[f'C{self.next_row}'] = 77
stotal[f'D{self.next_row}'] = 77
stotal[f'E{self.next_row}'] = 77
stotal[f'F{self.next_row}'] = 77
stotal[f'G{self.next_row}'] = 77
stotal[f'H{self.next_row}'] = 77
stotal[f'I{self.next_row}'] = 77
stotal[f'J{self.next_row}'] = 77
wb.save(f'{self.filepath}{self.filename}')
if __name__ == '__main__':
try:
wte = Writing_to_excel()
wte.get_next_row()
wte.write_data_to_excel()
logging.info(f"{wte.filename} 文件数据操作完成")
print(f"{wte.filename} 文件数据操作完成")
except Exception as e:
logging.error(f"{wte.filename}操作失败!原因:{e}")
print(e)