Python自动化办公_基于xlwings库Excel批量合并表单sheet于一个工作簿

项目要求:

摘要:根据所有工作簿中表单名称,合并至一个工作簿且包含所有工作表单

某项目的质检结果产生大量的工作簿,每个工作簿中包含不同的工作表单,要求把所有的工作簿按照表单名称合并至一个工作簿中。
项目格式如下图所示:
在这里插入图片描述

这样子的工作表格有100多个。
每个工作簿中的工作表单如下图所示
在这里插入图片描述
不仅限于这些,有的工作簿中要比这个工作表要多。
最终结果要求生成一个工作簿,这个工作簿中包含所有工作簿中的表单,并将所有工作簿按照工作表单进行合并至该工作簿。


问题思路

方法一:
1.遍历生成Excel路径的txt
2.遍历txt中的excel路径
3.形成表单名称集合
4.创建新的工作簿,根据集合创建表单
5.根据表单名称复制数据(合并)
6.保存

筛选
循环遍历txt
表单名称去重
创建
循环判断
存在
复制粘贴
不存在
遍历完成
遍历所有Excel文件名称
生成路径txt
每个工作簿中表单名称
生成AllSheetNamesList
形成表单名称集合AllSheetNamesSet
依据集合中的名称
在新的工作簿newworkbook中创建表单
表单名称是否存在
选中originsheet中所有内容
使用originsheet.api.usedrange
从原表复制到新工作簿中对应表单中
跳过
关闭打开的工作簿workbook.close
保存

方法二、

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.根据该程序可以举一反三,将一个表拆分成多个表格。

欢迎评论留言私信遇到的问题,共同学习进步!!
(原创不易,记得给我点赞关注,请多多支持,后续会继续更新自动化内容)

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

激动的兔子

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值