办公自动化

从多层文件夹的多个excel中统计汇总各个文件夹和各个excel的全部SHEET中的指定数据。

一个文件夹,里面有多个子文件夹和多个excel表格,每个子文件夹里面也有多个子文件夹和多个excel表格,每个excel表格中有若干个SHEET。
每个excel表是每个员工自己制作的表格,其中每个sheet存储着每个月的报销清单,每个文件夹分类存放着每个小组的表格,这些小组的表格又放在他们的部门文件夹里,每个部门的文件夹放在分公司的文件夹里,再按分公司命名后放到总公司的文件夹里。
现在要统计里面的金额和条目数,金额所在的列名,有的叫“(金 额)”,有的叫“B_A.金额”,这种里面只有“金额”两个汉字的要统计,还有的列叫“已报销金额”,这种的不能被统计。
(总之,文件夹很多,层次很深,表格文件很多,可能还有其他非表格文件,SHEET很多,奇葩列名也有)
统计结果要按分公司、部门、小组、员工的层级分组。

实现

我把各个分公司的文件夹放在同一个文件夹中,给这个文件夹起个名字,叫“文件放这里”,然后用python编程来搞定这个统计任务,运行之前保证这个文件夹的所有文件没有被其他软件占用。

import os
import re
import pandas as pd


class 目录树:
    def __init__(self):
        self.当前目录=''
        self.子树=[]
        self.表格文件=[]
        self.各文件的总金额=[]
        self.各文件的总人次=[]

def 构建树(目录):
    树 = 目录树()
    树.当前目录 = 目录
    for i in os.listdir(目录):
        path = 目录+os.sep+i
        #print('读取目录',path)
        if os.path.isdir(path):
            树.子树.append(构建树(path))
        elif os.path.isfile(path):
            if len(i)> 4 and i[-4:]=='.xls'or len(i)> 5 and i[-5:]=='.xlsx':
                树.表格文件.append(path)
                总金额=0
                总人次=0
                #读一下表格
                for df in pd.read_excel(path,sheet_name=None).values():
                    cs = df.columns.to_list()
                    #统计一下金额和人次(条目数)
                    for i in cs:
                        if '金额' == ''.join(re.findall("[^A-Za-z0-9_().\s]",i)):
                            总金额 += df[i].sum()
                            总人次 += df[i].count()
                            break
                树.各文件的总金额.append(总金额)
                树.各文件的总人次.append(总人次)
    return 树

def 遍历树(节点,索引表,索引栈,金额列表,人次列表):
    #节点入栈
    索引栈.append(os.path.basename(节点.当前目录))
    #遍历子节点
    for 子节点 in 节点.子树:
        遍历树(子节点,索引表,索引栈,金额列表,人次列表)
    #遍历文件
    for i in zip(节点.表格文件,节点.各文件的总金额,节点.各文件的总人次):
        索引栈.append(os.path.basename(i[0]).rstrip('.xlsx').rstrip('.xls'))
        索引表.append(tuple(索引栈[1:]))
        金额列表.append(i[1])
        人次列表.append(i[2])
        索引栈.pop(-1)
    #节点出栈
    索引栈.pop(-1)

path = os.getcwd()
l1 = os.listdir(path)
if '文件放这里' in l1:
    path = path+os.sep+'文件放这里'
    根节点 = 构建树(path)
    索引表=[]
    索引栈=[]
    人次列表=[]
    金额列表=[]
    遍历树(根节点,索引表,索引栈,金额列表,人次列表)

df = pd.DataFrame(索引表)
df['人次']=人次列表
df['金额']=金额列表
df = df.set_index([0,1,2,3])#分组层级有四层
df#这个df就是我要的结果

把多个excel文件中的SHEET1按其中的一列分组,每一组创建一个以该组的名称命名的文件夹,把每一组的数据放进一个excel表格(文件名还是原来的),再分别放到对应组的文件夹中。

解决方法就像是邮递员送信,把原始数据存放的文件夹(没有子文件夹)和新的文件夹、代码运行目录放在同一目录下,然后运行下面这个即可。有些列可能会从文本变为数字,如果不想改变需要在读取表格时设置converters。

import pandas as pd
import os
分组的列名="什么"
原始表格所在的文件夹='原始数据文件夹'
新表格存放的文件夹 = '新建文件夹'
for i in os.listdir(原始表格所在的文件夹):
    df = pd.read_excel('{}{}'.format(原始表格所在的文件夹,os.sep+i),converters={i:str for i in ['必需保留原文的列1的字段名','必需保留原文的列2的字段名']})
    a = df[分组的列名].drop_duplicates()
    for j in a.values:
        k = df[df[分组的列名]==j]
        r = k.set_index(df.columns.values[0])
        new_dir ='{}{}'.format(新表格存放的文件夹,os.sep+j)
        if not os.path.exists(new_dir):
            os.mkdir(new_dir)
        r.to_excel(new_dir+'{}.xlsx'.format(os.sep+i.split('.')[0]))

合并excel

在逐行读取CSV的时候,遇到换行符会被认为是不同的行,然而,有的数据项本身就存在换行符“\n”……

办法是加一个字段数校验,每次必须读入足够的内容:

with open('a.csv','r') as f:
    for line in f:
        s = line.split(',')
        print(s)
        l = len(s)
        break
    n0=eval('['+input('输入要统计求和的每个统计量的索引,用半角逗号分割:')+']')
    sum0=[0 for i in n0]
    is_all=True
    for line in f:
        print(line)
        if is_all:
            s = line.split(',')
        else:
            new = line.split(',')
            s[-1] = s[-1]+new[0]
            s += new[1:]
        if len(s)==l:
            is_all=True
            j=0
            for i in n0:
                sum0[j]+=eval(s[i])
                j+=1
        else:
            is_all=False
    print(sum0)

输出表格的格式怎么修改

参考这个:改to_excel()格式
写成python函数——直接在原有的表格上改变格式:

def format_excel(filepath):
    if filepath[-4:].lower()=='.xls' or filepath[-5:].lower()=='.xlsx':
        dfs= pd.read_excel(filepath,sheet_name=None)
        writer = pd.ExcelWriter(filepath,engine="xlsxwriter")
        for sname,df in dfs.items():
            for cname in df:
                #对长整数转换存储格式,避免精度丢失
                if df[cname].dtype == 'int64' and (df[cname]>9999999).any():
                    df[cname] = df[cname].astype('object')
            df.to_excel(writer, sheet_name=sname,index=False)
        #格式化输出
        workbook = writer.book
        worksheets = writer.sheets
        #在这里自定义表头格式
        header_format = workbook.add_format({'font_size': 9,'border': 0,'bold':True})
        ##在这里自定义每一列的单元格格式
        cell_format = workbook.add_format({'font_size': 9,'border': 0})
        for sname, df in dfs.items():
            worksheet = worksheets[sname]
            #每列改一遍
            for col_num, value in enumerate(df.columns.values):
                worksheet.write(0, col_num, value, header_format)
                worksheet.set_column(col_num,col_num, len(value)*1.6, cell_format)
        writer.save()
        writer.close()
        print('文件“{}”格式化已完成'.format(filepath))
    else:
        print('文件“{}”不是电子表格'.format(filepath))

(未完待续,更过功能,持续更新)

你可能感兴趣的:(办公自动化)