最近在折腾xlwings,工作中有一个需求就是把一个Excel文件中的多个sheets拆分为独立的Excel文件。之前用的是网上找到的vba代码。
但是既然想用xlwings代替vba,于是就寻找使用xlwings拆分sheets为单独文件的方法。
百度搜索了一圈,目前找到两种方法(详见附录),但都只是把值拆入到新Excel文件了,我想拆分时保留每个sheet的格式(字体、背景色、合并单元格之类)。
既然要保留各sheets的格式,最理想的办法莫过于复制每一个sheet为新的sheet,于是翻墙用Google搜索,找到了这个:
import xlwings as xw
wb = xw.Book('filename.xlsx')
sheet = wb.sheets['Sheet1']
#copy to a new workbook
sheet.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 xw
wb=xw.Book(filepath)
for sht in wb.sheets:
ws=wb.sheets[sht.name]
new=ws.api.Copy()
#最开始没有找到获取新工作簿的办法,所以用了个比较笨的办法
##new=xw.books[-1]
#找到了获取新工作簿的“正确”方法
new=xw.books.active
new.screen_updating=False
new.display_alerts=False
path="\\".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').value
column = Range('temp', 'AA2').value
data = 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/13
import os
import sys
import time
import xlwings as xw
class 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=False
app.screen_updating=False
wb=app.books.open(excel_name)
rng=wb.sheets["sheet1"].range("a2").expand("down")
rng_count=rng.count + 2
for obj in rng:
obj_value=obj.value
if obj_value not in site_list:
site_list.append(obj_value)
wb.save()
wb.close()
app.quit()
return site_list,rng_count,excel_name
def run(self):
app = xw.App(visible=False, add_book=False)
app.display_alerts = False
app.screen_updating = False
site_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 = 2
m = 2
wb_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).value
if str(site) in str(col_a):
col_d = wb.sheets["sheet1"].range("d%d" % n).value
col_e = wb.sheets["sheet1"].range("e%d" % n).value
col_r = wb.sheets["sheet1"].range("r%d" % n).value
wb_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 += 1
n += 1
wb_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()