好久没有写点东西了,突发奇想把工作中每日需要发送的日报使用python完成,就不需要每天都重复相似的工作N遍。工作日报需要从多个csv格式,整合为通一个excel的不同sheet,并对部分sheet进行数据透视汇总,并存储到当前日报文件中
import pandas as pd
# import datetime
import os
import configparser
# import time
import tkinter
def file_name(file_dir):
for root, dirs, files in os.walk(file_dir):
return files #当前路径下所有非目录子文件
def config_parser(cfgpr):
#如果没有配置文件则自动生成
config = configparser.ConfigParser()
if not os.path.exists(cfgpr):
config['Sys']={
}
config['Sys']['base_dir'] = r'python'
config['Sys']['date'] = '200520'
# config['Sys']['db_path']= '${base_dir}/${date}'
with open (cfgpr,'w') as f:
config.write(f)
return 1
try:
config_parser('config.ini')
config = configparser.ConfigParser()
config.read('config.ini') #读取配置文件,并提取需要的信息
date = config['Sys']['date']
filepath = config['Sys']['base_dir']
daliypath = os.path.join(filepath,date) #将配置文件中base_dir与date组合成新路径
os.chdir(daliypath) #切换至配置文件中配置‘base_dir+date’的目录
daliy_file = '调度日报汇总_'+date+'.xlsx' #定义每日日报xlsx名称
path_daliyfile = os.path.join(daliypath,daliy_file) #每日日报的绝对路径
except Exception as e:
print(e)
if not os.path.exists(daliypath):
"""
如果文件夹不存在,输出目录下不存在该文件夹
如果文件夹存在,且已存在每日日报文件,则删除该文件
"""
print('找不到指定的文件夹,请检查该日期文件夹是否在目录下:'+daliypath)
else:
if os.path.exists(path_daliyfile):
os.remove(path_daliyfile)
files = file_name(daliypath)
writer = pd.ExcelWriter(path_daliyfile)
try:
for file in files: # 遍历目录下所有文件
if file.endswith('.csv'): # 只需要CSV格式文件
if '每日调度汇总' in file:
# 每日调度记录需要获取的数据
df = pd.read_csv(file ,sep = ',' ,engine = 'python' ,quotechar='"',encoding = 'gbk').set_index('日期')
# print(df)
CellNum = df.loc[int(date),'全量']
ActCellNum = df.loc[int(date),'当天总数(剔重)']
ActMaxCell = df.loc[int(date),'最大数']
AdjustRate = df.loc[int(date),'频率(%)']
AdjustFrq = df.loc[int(date),'频次']
ActFrq = df.loc[int(date),'频次数(A)']
DeaFrq = df.loc[int(date),'频次数(D)']
AdjustCellNum = df.loc[int(date),'总数']
else:
# 其他CSV格式文件则全部汇总保存在同一个excel的不同sheet
print(os.getcwd())
print(file)
SheetName = file.split('_')[0] #按照csv格式的_分割成sheet名
df = pd.read_csv(file ,sep = ',' ,engine = 'python' ,quotechar='"',encoding = 'gbk')
if ('周期' in df.columns) or ('周期标识' in df.columns):
#如果CSV文本中有字段周期或者周期标识的列,则将该列转换为8位数的文本,不够8位数则前面补0
df.iloc[:,1]=df.iloc[:,1].astype(str).str.pad(8,fillchar="0") #周期标识或者周期均在第二列
df.to_excel(writer,sheet_name = SheetName, index = False)
writer.save()
else:
# os.remove(file)
print('存在有非CSV格式日报文件,不处理')
except Exception as e:
print(e)
try:
df2 = pd.read_excel(path_daliyfile,sheet_name = '历史调整记录',encoding = 'gbk')
# 从历史调整记录调整记录中筛选调整失败的放入其他sheet
df2 = df2[(df2['类型']=='ACT') &(df2['结果']=='失败') &(df2['报文'] != '成功')]
ActFaild = df2.shape[0] # 获取激活失败的总量,用在输出每日调整记录
df2.to_excel(writer,sheet_name = "历史调整记录_失败", index = False)
df3 = pd.pivot_table(df2, index =['报文'] ,values = ['日期'],aggfunc = 'count',dropna = True).reset_index().rename(columns ={
'报文':'失败详情','日期':'数量'})
# 类似excell的数据透视表,汇总数据
df3.to_excel(writer,sheet_name = "失败", index = False)
writer.save()
print('每日调度汇总这样输出!\n') # 输出每日调整记录
listdate = list(date)
listdate.insert(2,'年') # 在200520中插入年月变成20年05月20
listdate.insert(5,'月')
message = ('{}日全量为{},当天总数(剔重){},当天最大数{},频率{}%,频次{},频次数(A){},频次数(D){},调度总数{},失败{}个;'.format(''.join(listdate),int(CellNum) , int(ActCellNum) , int(ActMaxCell) , AdjustRate , int(AdjustFrq) , int(ActFrq), int(DeaFrq) , int(AdjustCellNum) , int(ActFaild)))
print(message)
with open('message.txt','w') as f:
f.write(message) # 每日简报再保存一份到txt中
except Exception as e:
print(e)
writer.close() # 关闭excel
Print_Msg =tkinter.Tk()
Print_Msg.title("Daliy") # 设置窗口标题
Print_Msg.geometry("300x240") #指定窗口大小
ms = tkinter.Message(Print_Msg,text=message) # Message可以自动换行文本
ms.pack()#给相应的组件指定布局
Print_Msg.mainloop() #进入消息循环,没有这句窗体不会呈现
pyinstaller -F -i xxx.ico xxxx.pyw
ico为图标,pyw为py源代码文件,后面加w是为了运行过程中不出现cmd的黑窗口
df2["周期标识"]=df2["周期标识"].astype(str).str.pad(8,fillchar="0")
pandas中字符串格式使用object标识,如果astype(object)仍然会报AttributeError,一定要astype(str)才可以
2、在使用EXCEL的数据透视表时,如果要计算单独一列的不同单元格的计数或者求和,将该列拖入到《行》或者《列》区间,再把该列拖入到《值》中,完成数据汇总
pandas中pivot_table则不行,index与values值相同,会报ValueError,我这里解决方法是选择另外一列作为计数列:
df3 = pd.pivot_table(df2, index =['报文'] ,values = ['日期'],aggfunc = 'count',dropna = True).reset_index().rename(columns ={
'报文':'失败详情','日期':'数量'})