Find For You

                        ——  只为更高效的服务
首页 > 公告

长歌行

2023年11月24日

含子文件夹遍历整合数据-去除密码

"""
   用来遍历文件夹下(包括子目录内递归遍历)所有 excel 文件,批量执行
"""
import locale
import os, io
import pandas as pd
import datetime
import msoffcrypto

# 打印出一个目录下所有的末级文件名称
"""
   os.walk()文件目录遍历器
   语法:os.walk(top),top为需要遍历的目录地址,返回一个三元组(root,dirs,files)。
   1)root 所指的是当前正在遍历的这个文件夹的本身的地址
   2)dirs 是一个 list ,内容是该文件夹中所有的目录的名字(不包括子目录)
   3)files 同样是 list , 内容是该文件夹中所有的文件名称(不包括子目录)
   for root, dirs, files in os.walk(r"/Users/hh/Downloads/附件合集"):
   
       # print(root,'root')
       # print(dirs,'dirs')
       print(files, 'files')
"""


class MYData(object):

   def __init__(self, file_str, password, eligible_list, eligible_sheet, exclude, extensions, output_path):
       self.password = password
       # 根文件夹路径
       self.file_str = file_str
       # 输出的整理好的表格数据
       self.__dfs = pd.DataFrame()
       # 输出的执行过的文件
       self.__list_s = []
       # 有资格参与数据处理的 excel 关键字,用来判断 excel 名字里是否包含
       self.eligible_list = eligible_list
       self.eligible_sheet = eligible_sheet
       self.exclude = exclude
       self.extensions = extensions
       self.output_path = output_path

   def __is_Eligible(self, file_name):
       """
       判断 exle 是否符合特殊要求
       :param file_name:
       :return:
       """
       if file_name.startswith('~'):
           return False
       if file_name.endswith(".xlsx") or file_name.endswith(".xls"):
           # str_list = ['生产工艺', '质量文件', '引物探针', '序列']
           search_str = file_name
           if any(substring in search_str for substring in self.eligible_list):
               print('工作薄名称是否包含所需关键字:True', search_str, self.eligible_list)
               return True
           else:
               print('工作薄名称是否包含所需关键字:False', search_str, self.eligible_list)
               return False
       return False

   def __isExcelEncrypted(self, file_name):
       """
       判断 excel 是否加密
       :return: True or False
       """
       try:
           fileHandle = open(file_name, "rb")
           ofile = msoffcrypto.OfficeFile(fileHandle)
           isEncrypted = ofile.is_encrypted()
           fileHandle.close()
           return isEncrypted
       except Exception as err:
           return "Exception: " + str(format(err))

   def __add_dfs(self, df):
       """
       增加到 DataFarm 用于 pandas 处理数据
       :param df: 每个 excel 的 df
       :return:
       """
       self.__dfs = pd.concat([self.__dfs, df], axis=0, copy=True)

   def __add_list_s(self, file_name, sheetname):
       """
       增加执行的文件列表,拼接一起存入列表
       :param root_dir: 执行目录路径
       :param file: 文件名字
       :return:
       """
       self.__list_s.append(f'{file_name}|{sheetname}')

   def __processing_sheet_data(self, sheet, file_name, root_dir, file):
       """
       处理 sheet 表,读数据写到 DF 里面
       :param sheet: 传递 sheet 名字
       :param file_name: 具体路径全路径
       :param root_dir: 路径
       :param file: 文件名字
       :return:
       """
       str_list = self.eligible_sheet
       search_str = sheet

       if any(substring in search_str for substring in str_list):
           print('True  sheet是否包含关键字', search_str, str_list)
           df = pd.read_excel(file_name, sheet_name=sheet, header=1)
           print(df.columns, df.index, df.shape, df.size,
                 "header ==1 ")
           my_list = df.columns
           substring = 'Unnamed: 3'
           result = any(substring in str(word) for word in my_list)
           print(result)
           if result:
               df = pd.read_excel(file_name, sheet_name=sheet, header=2)
               print(df.columns, df.index, df.shape, df.size,
                     "header ==2 ")
               my_list = df.columns
               substring = 'Unnamed:'
               result = any(substring in str(word) for word in my_list)
               result_2 = [word for word in my_list if substring in str(word)]

               if len(result_2) > 2:
                   df = pd.read_excel(file_name, sheet_name=sheet, header=3)

                   print(df.columns, df.index, df.shape, df.size, "header ==3 ")
                   print(result_2, type(result_2), len(result_2))
                   print(len(result_2))

           df["excel_name"] = os.path.join(root_dir, file)
           df["sheet_name"] = sheet
           print(df.info())
           self.__add_dfs(df)
           self.__add_list_s(file_name=os.path.join(root_dir, file), sheetname=sheet)

       else:
           print('查找后没有不包含啊!False', f'【工作表{search_str}】', f'关键字:{self.eligible_list}')

   def __workbook_not_encrypted(self, *args, **kwargs):
       root_dir = kwargs.get("root_dir", None)
       file = kwargs.get("file", None)
       file_name = kwargs.get("file_name", None)
       # 执行遍历把 sheet 传递到函数去处理
       sheet_keys = pd.read_excel(file_name, sheet_name=None).keys()

       # 把执行过的文件保存下来到指定文件
       import shutil
       # 剪切工作表到新地址
       # os.replace(file_name, os.path.join(self.output_path, file))
       # 复制工作表到新地址
       strroot = '[' + str(root_dir).replace('/', '-').split('-')[-1] + '] '
       shutil.copy2(file_name, os.path.join(self.output_path, strroot + file))

       print('+++++++++++++++++++++++++++++++++++++++', file_name)
       for sheet in sheet_keys:

           print(sheet, '-----------', sheet_keys)
           print('+++++++++++++++++++++++++++++++++++++++')
           try:
               self.__processing_sheet_data(sheet=sheet, file_name=file_name, root_dir=root_dir, file=file)
           except Exception as e:
               print(e, '这里可是不加密 excel 的处理哦!')
               self.__add_list_s(file_name=os.path.join(root_dir, file), sheetname=e)
               return False

   def __workbook_is_encrypted(self, *args, **kwargs):
       root_dir = kwargs.get("root_dir", None)
       file = kwargs.get("file", None)
       root_dir = kwargs.get("root_dir", None)
       file_name = kwargs.get("file_name", None)
       file_temp = io.BytesIO()
       # 打开加密文件
       with open(file_name, 'rb') as f:
           fileExcel = msoffcrypto.OfficeFile(f)
           try:
               fileExcel.load_key(self.password)
               fileExcel.decrypt(file_temp)
               # 顺便把解密的文件保存到指定目录
               strroot = '[加密#' + str(root_dir).replace('/', '-').split('-')[-1] + '] '
               # 把读到了内存中的表另存到新的地址,不会变更原始位置的表
               fileExcel.decrypt(open(os.path.join(self.output_path, strroot + file), 'wb'))

               sheet_keys = pd.read_excel(io=file_temp, sheet_name=None, ).keys()
               print('------------------------------------------------', file_name)
               for sheet in sheet_keys:
                   print(sheet, '-----------', sheet_keys)
                   self.__processing_sheet_data(sheet=sheet, file_name=file_temp, root_dir=root_dir, file=file)
               return None, None
           except Exception as e:
               print(e, '加密解开错误,或许也是文件 utf-16-e的问题')
               self.__add_list_s(file_name=os.path.join(root_dir, file), sheetname=e)
               return False, e
   @property
   def goto_excel(self):
       # os.walk(file_path) 深度遍历file_path下的所有子文件夹及文件

       for root_dir, sub_dir, files in os.walk(self.file_str):

           sub_dir[:] = [d for d in sub_dir if d not in self.exclude]
           # os.path.splitext是Python标准库中的一个函数,它可以将一个文件路径拆分成两部分:文件名和文件扩展名
           files = [file for file in files if os.path.splitext(file)[1] in self.extensions]

           for file in files:
               # 判断哪些 excel 是否和条件的则处理, 条件罗列在初始化类的时候定义
               if self.__is_Eligible(file):
                   # 构造绝对路径
                   file_name = os.path.join(root_dir, file)

                   isExcelEncrypted = self.__isExcelEncrypted(file_name)
                   print(f'是否加密{isExcelEncrypted};当前执行的文件是:{file_name}')
                   if not isExcelEncrypted:
                       print(file_name, '++++++++++++++++++++++++++++++++++++++++++++++++++正常未加密的 excle')

                       self.__workbook_not_encrypted(file_name=file_name, file=file, root_dir=root_dir, )
                       print('<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<')
                   else:
                       print(file_name, '---------------------------------------------------处理加密的 excle')
                       # 当密码解密文件不对的时候返回  一个 False,判断后记录下来
                       failed_to_verify_password, f_e = self.__workbook_is_encrypted(file_name=file_name, file=file,
                                                                                     root_dir=root_dir, )
                       print(failed_to_verify_password, f_e)
                       # if failed_to_verify_password == False:
                       #     self.__add_list_s(file_name=os.path.join(root_dir, file), sheetname=f'{f_e} 可能被重复记录')
                       print('>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>')

                   # try:
                   #     """
                   #         这里 try 的目的是为了测试读取常规的 excel 的时候是否报错,报错的话尝试使用 解密输入密码打开 excel
                   #         # 读取sheet页
                   #         # pd.read_excel(file_path,sheet_name=None).keys()获取excel表格所有的sheet页名称
                   #     """
                   #     print(file_name, '+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++正常 excle')
                   #     sheet_keys = pd.read_excel(file_name, sheet_name=None).keys()
                   #     self.__workbook_not_encrypted(file_name= file_name, file= file, root_dir= root_dir,
                   #                                 sheet_keys= sheet_keys,)
                   #     # for sheet in sheet_keys:
                   #     #     print(sheet, )
                   #     #     print('+++++++++++++++++++++++++++++++++++++++')
                   #     #     df = pd.read_excel(file_name, sheet_name=sheet, header=1)
                   #     #     df["excel_name"] = file
                   #     #     df["sheet_name"] = sheet
                   #     #     # excel_name=file.replace(".xlsx","")
                   #     #     # 新增两列用于记录数据所属excel及sheet页,这一步骤感觉很有用,因为后续数据清理的时候,遇到莫名其妙的数据不知道怎么办的话,还可以去源excel表格上看下。
                   #     #     # 写入输出 excel 文件
                   #     #     # print(df[:5])
                   #     #     self.__add_dfs(df)
                   #     #     self.__add_list_s(root_dir, file)
                   #
                   # except Exception as e:
                   #     print(file_name, e, '----------------------------------------------------------处理加密的 excle')
                   #     """
                   #         处理加密的 excle
                   #
                   #                 file_temp = io.BytesIO()
                   #                 with open(file_name, 'rb') as f:
                   #                     fileExcel = msoffcrypto.OfficeFile(f)
                   #                     fileExcel.load_key(self.password)
                   #                     fileExcel.decrypt(file_temp)
                   #                     # 循环一个工作簿内所有工作表 sheets
                   #                 for sheet in pd.read_excel(io=file_temp, sheet_name=None).keys():
                   #                 # df = pd.read_excel(io=file_temp, sheet_name=sheet, header=1, )
                   #                 # df["excel_name"] = file
                   #                 # df["sheet_name"] = sheet
                   #                 # excel_name=file.replace(".xlsx","")
                   #                 # 新增两列用于记录数据所属excel及sheet页,这一步骤感觉很有用,因为后续数据清理的时候,遇到莫名其妙的数据不知道怎么办的话,还可以去源excel表格上看下。
                   #                 # 写入输出 excel 文件
                   #                 # print(df[:5])
                   #                 # self.__add_dfs(df)
                   #                 # self.__add_list_s(root_dir, file)
                   #     """
                   #     self.__workbook_is_encrypted(file_name= file_name, file= file, root_dir= root_dir,)

       print("---------------执行结束——————————————")
       # 执行的文件路径和名字
       print(self.__list_s)
       for l in self.__list_s:
           print(l)
       dflist = pd.DataFrame(self.__list_s)
       dflist.to_excel(f'{self.output_path}/执行文件列表.xlsx')
       self.__dfs.to_excel(f'{self.output_path}/合并数据.xlsx')


pd.set_option('display.max_columns', None)  # 设置列
pd.set_option('display.max_rows', None)  # 设置行


def main():
   # 实例化干活的类,参数file_str是执行的路径,把加密的 excel 密码传递进去,
   # 参数str_list = ['生产工艺', '引物探针', '序列'] 控制哪些 excel 进行处理

   # 在这里定义自己的路径地址,要处理的文件夹: file_str=r" 这里输入文件夹地址 "
   my_data = MYData(file_str=r"/Users/hh/Downloads/2023年日报",
                    # 锁定的工作表的密码
                    password='zchscdc',
                    # 我要的工作簿名称关键词,包含就可以
                    eligible_list=['马小云', ],
                    # 我要的 sheet 的名字关键词
                    eligible_sheet=['Sheet1', ],
                    # 排除文件夹的名字,不排除就保持空列表即可 ['文件夹名字 1', '文件夹名字 2', ]
                    exclude=[],
                    # 需要的文件类型,后缀
                    extensions=['.xlsx', '.xls'],
                    # 输出文件的文件夹,这里本程序输入 整合数据及加密表格的解密版本
                    output_path=r'/Users/hh/Downloads/电影天堂'
                    )

   # 执行goto_excel方法 ,参数output_path是指定的输出目录位置
   my_data.goto_excel
   """
       # 这种写法尅访问私有变量,私有方法(对封装的一种破解),也可以进行修改
       # my_data._MYData__list_s=[]
       # print(my_data._MYData__list_s)
   """
   [print(i, f'列标推导式循环{str(i).split("/")}') for i in my_data._MYData__list_s]


if __name__ == '__main__':
   print('main……………………………………………………………………………start………………………………………………………………………………………')
   main()

   # import os

   # exclude = set([]) # 排除文件夹的名字
   # extensions = set(['.xlsx', '.docx','.xls'])  # 需要的文件类型,后缀
   # for root, dirs, files in os.walk(r"/Users/hh/Documents", topdown=True):
   #     """
   #     参数
   #         top -- 是你所要遍历的目录的地址, 返回的是一个三元组(root,dirs,files)。
   #         root 所指的是当前正在遍历的这个文件夹的本身的地址
   #         dirs 是一个 list ,内容是该文件夹中所有的目录的名字(不包括子目录)
   #         files 同样是 list , 内容是该文件夹中所有的文件(不包括子目录)
   #         topdown --可选,为 True,则优先遍历 top 目录,否则优先遍历 top 的子目录(默认为开启)。如果 topdown 参数为 True,walk 会遍历top文件夹,与top 文件夹中每一个子目录。
   #         onerror -- 可选,需要一个 callable 对象,当 walk 需要异常时,会调用。
   #         followlinks -- 可选,如果为 True,则会遍历目录下的快捷方式(linux 下是软连接 symbolic link )实际所指的目录(默认关闭),如果为 False,则优先遍历 top 的子目录。
   #     """
   #     dirs[:] = [d for d in dirs if d not in exclude]
   #     # os.path.splitext是Python标准库中的一个函数,它可以将一个文件路径拆分成两部分:文件名和文件扩展名
   #     files = [file for file in files if os.path.splitext(file)[1] in extensions]
   #
   #     print(root,'root')
   #     print(dirs, "dirs")
   #     print(files,"files")
   #     print('👇🏻')
   #     for fname in files:
   #         print(os.path.join(root,fname))
   #     print('++++++++++++++++++++++++++++++')

   print('over………………………………………………………………………………main……………………………………………………………………………………')