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……………………………………………………………………………………')