Python学习之路|目录下所有CSV文件汇总至EXCEL

遍历目录下所有CSV文件并汇总至EXCEL

  • 前言
  • 构思过程
  • 详细代码
  • 打包指令
  • 踩过的坑

前言

好久没有写点东西了,突发奇想把工作中每日需要发送的日报使用python完成,就不需要每天都重复相似的工作N遍。工作日报需要从多个csv格式,整合为通一个excel的不同sheet,并对部分sheet进行数据透视汇总,并存储到当前日报文件中

构思过程

  1. 读取目录下所有文件 ,使用os模块os.walk获取;
  2. 读取CSV文件并保存到excel,使用pandas模块的read_csv与to_excel完成
  3. 数据透视汇总,使用pandas中的pivot_table完成
  4. 不同服务器上使用目录不同,使用configparser模块在当前目录生成默认配置文件
  5. 了解每日大致信息,使用tkinter模块,在窗体输出简报
  6. 代码打包成exe,使用pyinstaller将代码打包exe使用

详细代码

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的黑窗口

踩过的坑

  1. 由于输出保存在excel中想得到周期标识列为8位字符串,不够的前面补0,而传递的csv周期标识列会转化为整数,需要再次转化为字符串,且前面自动补零
    使用pandas的str.pad()函数补齐,运行后报AttributeError:需要将原列转化为字符串类型,然后再执行:
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 ={
     '报文':'失败详情','日期':'数量'})

你可能感兴趣的:(python,csv,excel)