项目要求:
摘要:根据所有工作簿中表单名称,合并至一个工作簿且包含所有工作表单
某项目的质检结果产生大量的工作簿,每个工作簿中包含不同的工作表单,要求把所有的工作簿按照表单名称合并至一个工作簿中。
项目格式如下图所示:
这样子的工作表格有100多个。
每个工作簿中的工作表单如下图所示
不仅限于这些,有的工作簿中要比这个工作表要多。
最终结果要求生成一个工作簿,这个工作簿中包含所有工作簿中的表单,并将所有工作簿按照工作表单进行合并至该工作簿。
问题思路
方法一:
1.遍历生成Excel路径的txt
2.遍历txt中的excel路径
3.形成表单名称集合
4.创建新的工作簿,根据集合创建表单
5.根据表单名称复制数据(合并)
6.保存
方法二、
Excel2016以上版本是不是可以直接批量合并表格?
还没有测试,后续会更新测试文章。
运行环境
1.VSCode或Jupyter
2.python 3.7.0
3.Excel2013以上均可以
解决方案:
完整代码如下:
1.自定义函数
##首先运行所有定义函数!!!!
import re,os
#字符插入函数
def InsertIntoString(str_origin,pos,str_add):
#str_origin:源字符串
#pos:在字符串中的位置
#str_add:需要插入的字符或字符串
str_list=list(str_origin) #将原始字符串转换为list
str_list.insert(pos,str_add) #在指定位置插入字符串
str_out="".join(str_list) #使用空字符连接
return str_out
#写入到txt的函数
def WriteToTXT(txtpath,content):
#txtpat:保存路径
#content:写入的内容
with open(txtpath,"a") as f:
f.write(content)
# f.close()
#检查文件是否存在
def CheckFileExist(filepath):
return os.path.exists(filepath)
#删除文件
def DelteFile(filepath):
os.remove(filepath)
print (f"'{filepath}'文件重复,已经覆盖写入...\n\n")
#提取数字包含正负号(正负号数量不限)
def ExtractNumber(str):
pattern=re.compile("-*\+*\d+\.\d+|-*\+*\d+")
return pattern.findall(str)
#读取txt中文本的路径,并检查路径是否有效
#读取txt内文件路径
def Readtext(path):
FList=[]
with open(path,'r') as f :
for line in f.readlines():
l=line.strip('\n')
#logging.debug(l)
FList.append(l)
return FList
2 生成txt文件
#测试成功
#遍历所有文件的路径并保存在txt中
if __name__=="__main__":
#---------------设置参数start-------------------------------
#设置TXT保存的位置,TXT内存放遍历文件所获的的路径
SaveAstxt=r"D:\Desktop\合并测试\路径.txt"
SaveAstxtformat=InsertIntoString(SaveAstxt,-4,"_添加python识别格式")
#设置遍历的位置
Workenvironment=r"D:\Desktop\合并测试\分市表6"
#---------------设置参数end---------------------------------
if CheckFileExist(SaveAstxt):
DelteFile(SaveAstxt)
if CheckFileExist(SaveAstxtformat):
DelteFile(SaveAstxtformat)
for root,DirList,fileNameList in os.walk(Workenvironment):
for filename in fileNameList:
#---------------设置参数end---------------------------------
#文件过滤 *.xls|*.xlsx 如果不做过滤请注释掉以下代码
if ".xls" in filename:
#---------------设置参数start-------------------------------
print (os.path.join(root,filename))
#保存为常规路径
WriteToTXT(SaveAstxt,os.path.join(root,filename)+"\n")
#保存为带格式的路径
WriteToTXT(SaveAstxtformat,f'r"{os.path.join(root,filename)}",\n')
print (f"\n\n遍历完成,已将结果保存在'{SaveAstxt}'中")
3.获取表单名称集合
#测试成功
#获取所有工作簿book中工作表单sheet的名称,并根据sheet表名称创建sheet,合并表单
import xlwings as xw
app=xw.App(visible=False,add_book=False)
xlspth=Readtext(SaveAstxt)
AllSheetNamesList=[]
for exls in xlspth:
print (exls)
workbook=app.books.open(exls) # <class 'xlwings.main.Sheets'>
for sheet in workbook.sheets:
# sheet.name=sheet.name.replace("sheet","表格") #sheet重命名
print(sheet.name)
AllSheetNamesList.append(sheet.name)
#循环完成后关闭表单,否则程序会出现“是否允许读写的弹窗”
workbook.close()
# 创建集合,去重重复sheet名称,并从小到大排序
AllSheetNamesSet=sorted(set(AllSheetNamesList),reverse=False)
app.quit()
print (AllSheetNamesSet)
print ("Run successfully")
4. 合并表格
#测试成功
#获取所有工作簿book中工作表单sheet的名称,并根据sheet表名称创建sheet,合并表单
import xlwings as xw
app=xw.App(visible=False,add_book=False)
# app2=xw.App(r"D:\Desktop\合并测试\AllexcelMergedbk.xlsx",visible=False,add_book=False)
newworkbook=app.books.add() #新建工作簿
newsht = newworkbook.sheets.active
xlspth=Readtext(SaveAstxt)
# AllSheetNamesSet=['1101', '1301', '2301', '2302', '2401', '2501', '2701', '3101', '3401', '5101']
for sh_name in AllSheetNamesSet:
# if sh_name in[i.name for i in newworkbook.sheets]:
if sh_name in [i.name for i in newworkbook.sheets]:
newsht2=newworkbook.sheets[sh_name]
for exls in xlspth:
NewAllcell = newsht2.range('a1').expand('table')
#type(Allcell) #<class 'xlwings.main.Range'>
newrows = NewAllcell.rows.count #获取最大行数 ,其中已知列数为9,无需获取
workbook=app.books.open(exls)
if sh_name in [i.name for i in workbook.sheets]: #遍历已有表格中的sheet名称
originsheet=workbook.sheets[sh_name]
'''选择sheet页面最右下角的单元格,获取最大行数,和列数'''
# 区别 expand(), expand()只选中与之连续的单元格。
# Allcell = originsheet.used_range.last_cell #used_range属性不存在
Allcell = originsheet.api.usedrange #测试通过
# Allcell = originsheet.range('a1').expand('table')
#type(Allcell)<class 'xlwings.main.Range'>
orows = Allcell.rows.count #获取最大行数
ocolumns = Allcell.columns.count
print (f"{sh_name}--{orows}x{ocolumns}")
# columns = Allcell.columns.count
# if sh_name not in [i.name for i in newworkbook.sheets]:
print (f"{sh_name}---{exls}")
newsht2.range('A:I').api.NumberFormat ="@" #将科学计数的单元格转换为文本格式
my_values = originsheet.range(f'A1:W{orows}').options(ndim=2).value # 读取二维的数据
newsht2.range(f'A{1+newrows}').value = my_values
newsht2.range(f'X{1+newrows}:X{newrows+orows}').value =str(exls).split("\\")[-1]
newsht2.autofit() # 自动调整单元格大小。注:此方法是在单元格写入内容后,再使用,才有效。
#循环完成后关闭表单,否则程序会出现“是否允许读写的弹窗”
workbook.close()
else:
print (f"{sh_name}-----该sheet不存在,跳过------{exls}")
#循环完成后关闭表单,否则程序会出现“是否允许读写的弹窗”
workbook.close()
else:
newsht2 = newworkbook.sheets.add(sh_name, before=newsht) # 新建工作表,放在newsht工作表前面。
# newsht2 = newworkbook.sheets.add(sh_name, before=newsht) # 新建工作表,放在newsht工作表前面。
for exls in xlspth:
NewAllcell = newsht2.range('a1').expand('table')
#type(Allcell) #<class 'xlwings.main.Range'>
newrows = NewAllcell.rows.count #获取最大行数 ,其中已知列数为9,无需获取
workbook=app.books.open(exls)
if sh_name in [i.name for i in workbook.sheets]: #遍历已有表格中的sheet名称
originsheet=workbook.sheets[sh_name]
'''选择sheet页面最右下角的单元格,获取最大行数,和列数'''
# 区别 expand(), expand()只选中与之连续的单元格。
# Allcell = originsheet.used_range.last_cell #used_range属性不存在
Allcell = originsheet.api.usedrange #测试通过
# Allcell = originsheet.range('a1').expand('table')
#type(Allcell)<class 'xlwings.main.Range'>
orows = Allcell.rows.count #获取最大行数
ocolumns = Allcell.columns.count
print (f"表{sh_name}--共{orows}行x{ocolumns}列---{exls}")
# columns = Allcell.columns.count
# if sh_name not in [i.name for i in newworkbook.sheets]:
# print (f"{sh_name}---{exls}")
newsht2.range('A:I').api.NumberFormat ="@" #将科学计数的单元格转换为文本格式
my_values = originsheet.range(f'A1:J{orows}').options(ndim=2).value # 读取二维的数据
newsht2.range(f'B{1+newrows}').value = my_values
newsht2.range(f'A{1+newrows}:A{newrows+orows}').value =str(exls).split("\\")[-1]
newsht2.autofit() # 自动调整单元格大小。注:此方法是在单元格写入内容后,再使用,才有效。
#循环完成后关闭表单,否则程序会出现“是否允许读写的弹窗”
workbook.close()
else:
print (f"{sh_name}-----该sheet不存在,跳过------{exls}")
#循环完成后关闭表单,否则程序会出现“是否允许读写的弹窗”
workbook.close()
#删除多余的sheet
# for i in ["Sheet1","Sheet2","Sheet3"]:
# newworkbook.sheets[i].delete()
#设置合并后Excel的保存路径。
newworkbook.save(r"D:\Desktop\合并测试\质检结果合并.xlsx")
# workbook.save()
app.quit()
print ("运行完毕!")
小结
1.该程序对于格式规范的数据合并比较友好
2.对于格式不规范的数据需要做数据预处理,规范数据后效果会更佳
3.该程序仍需要半自动化设置(设置需要合并的列)
4.程序运行效率比较低,需要进一步优化
5.根据该程序可以举一反三,将一个表拆分成多个表格。
欢迎评论留言私信遇到的问题,共同学习进步!!
(原创不易,记得给我点赞关注,请多多支持,后续会继续更新自动化内容)