最近在折腾xlwings,工作中有一个需求就是把一个Excel文件中的多个sheets拆分为独立的Excel文件。之前用的是网上找到的vba代码。
但是既然想用xlwings代替vba,于是就寻找使用xlwings拆分sheets为单独文件的方法。
百度搜索了一圈,目前找到两种方法(详见附录),但都只是把值拆入到新Excel文件了,我想拆分时保留每个sheet的格式(字体、背景色、合并单元格之类)。
既然要保留各sheets的格式,最理想的办法莫过于复制每一个sheet为新的sheet,于是翻墙用Google搜索,找到了这个:
import xlwings as xwwb = xw.Book('filename.xlsx')sheet = wb.sheets['Sheet1']#copy to a new workbooksheet.api.Copy()
上面代码解决了单个sheet的复制问题,但是没解决:
- 多个sheets如何复制
- 复制出来的每个sheets如何保存为单独的Excel文件
解决办法
既然有单个sheet的复制方法,多个sheets复制就很简单,加一个循环就行了。
保存复制每一个sheet后新生成的workbook,我没找到优雅的办法,就用了个比较笨的办法:直接即对对象【xw.books.active】进行保存和关闭操作。
用xw.books获取所有打开的workbooks列表,由于在jupyter notebook代码中,我首先打开的是包含多个sheets的原始文件(叫《xlwings.xlsx》),而复制sheet后产生的新workbook位于它后面,所以用xw.books获取的列表最后一项(xw.books[-1])就是新的workbook,然后对其使用save()方法和close()方法即可。
查询excel的vba文档(看来还是绕不开vba)可知,copy()方法不加参数,就会生成一个新的workbook对象,并且自动激活为当前的workbook对象。利用这个特性可以获取新生成的workbook对象并对其进行操作。
新的文件名就用原始文档中各sheet的name【sht.name】。
就将拆分的文件放到原始文件的同一个文件夹下。
最后的代码如下:
def xw_splitter(filepath):import xlwings as xwwb=xw.Book(filepath)for sht in wb.sheets:ws=wb.sheets[sht.name]new=ws.api.Copy()#最开始没有找到获取新工作簿的办法,所以用了个比较笨的办法##new=xw.books[-1]#找到了获取新工作簿的“正确”方法new=xw.books.activenew.screen_updating=Falsenew.display_alerts=Falsepath="\\".join(filepath.split("\\")[:-1])new.save(r"{}\{}.xlsx".format(path,sht.name))new.close()
附录:不保留格式拆分sheets到单独Excel文件的两种方法:
def split_worksheets():wb = Workbook.caller()sheet = Range('temp', 'AA1').valuecolumn = Range('temp', 'AA2').valuedata = pd.DataFrame(pd.read_excel(sheet, 0, index_col=None, na_values=[0]))data.sort(column, axis = 0, inplace = True)split = data.groupby(column)for i in split.groups:Sheet.add()Range('A1', index=False).value = split.get_group(i)
#!/usr/bin/python# Author:Liu Jin Dong# Date:2019/5/13import osimport sysimport timeimport xlwings as xwclass SplitExcel(object):def __init__(self):self.path = os.path.abspath(os.path.dirname(__file__))self.time = time.strftime("%Y%m%d", time.localtime(time.time()))def get_site_list(self):split_excel=input("\033[32;1mExcel Name>>>:\033[0m").strip()excel_name=os.path.join(self.path,split_excel)if len(excel_name)==0 or os.path.isfile(excel_name) is None:print("\033[31;1mExcel File not found...\033[0m")sys.exit(0)site_list=[]app=xw.App(visible=False,add_book=False)app.display_alerts=Falseapp.screen_updating=Falsewb=app.books.open(excel_name)rng=wb.sheets["sheet1"].range("a2").expand("down")rng_count=rng.count + 2for obj in rng:obj_value=obj.valueif obj_value not in site_list:site_list.append(obj_value)wb.save()wb.close()app.quit()return site_list,rng_count,excel_namedef run(self):app = xw.App(visible=False, add_book=False)app.display_alerts = Falseapp.screen_updating = Falsesite_list,rng_count,excel_name=self.get_site_list()print(site_list)wb=app.books.open(excel_name)for site in site_list:file_x = os.path.join(self.path, "%s_%s.xlsx" % (str(site), str(self.time)))wb_x = app.books.add()n = 2m = 2wb_x.sheets["sheet1"].range("a1").value = "接入来源"wb_x.sheets["sheet1"].range("b1").value = "点位名称"wb_x.sheets["sheet1"].range("c1").value = "设备国标ID"wb_x.sheets["sheet1"].range("d1").value = "最后人像上传日期"while n < rng_count:col_a = wb.sheets["sheet1"].range("a%d" % n).valueif str(site) in str(col_a):col_d = wb.sheets["sheet1"].range("d%d" % n).valuecol_e = wb.sheets["sheet1"].range("e%d" % n).valuecol_r = wb.sheets["sheet1"].range("r%d" % n).valuewb_x.sheets["sheet1"].range("a%d" % m).value = str(col_a)wb_x.sheets["sheet1"].range("b%d" % m).value = str(col_d)wb_x.sheets["sheet1"].range("c%d" % m).value = "'" + str(col_e)wb_x.sheets["sheet1"].range("d%d" % m).value = str(col_r)print(wb_x.sheets["sheet1"].range("a%d" % m).value)print(wb_x.sheets["sheet1"].range("b%d" % m).value)print(wb_x.sheets["sheet1"].range("c%d" % m).value)print(wb_x.sheets["sheet1"].range("d%d" % m).value)print(n)print(m)m += 1n += 1wb_x.save(file_x)wb_x.close()else:print("\033[32;1mJob is Done...\033[0m")wb.save()wb.close()app.quit()if __name__ == "__main__":split_excel = SplitExcel()split_excel.run()
