如何使用openpyxl保存带有宏的XLSM文件。

28

我有一个带有宏功能的.xlsm文档。我正在使用openpyxl加载它,并向文档写入一些数据,最后想将其保存为不同的.xlsm文件。

为了将文件保存为XLSM文件,我在我的Python脚本中使用了下面的代码。

wb.save('testsave.xlsm');

如果我按照上述方式保存,我将无法打开该文件。但是如果我将其保存为.xlsx,那么我可以打开原始文件中具有宏功能的文件。

我想打开一个带有宏功能的Excel表格,编辑该文件,并使用openpyxl将其另存为新的.xlsm文件。我该怎么做?

6个回答

44

可以在Python中调用和运行宏吗? - ctrl-alt-delete
如果您已经安装了MS Office并且正在运行Windows,则可以使用OLE api来运行它。否则,您必须使用Python中的openpyxl重新设计宏代码。 - eule
这个链接与xlsm无关!实际上,如果你访问http://openpyxl.readthedocs.io/en/latest/usage.html?highlight=xlsm,你会发现没有任何东西被突出显示,因为那里根本没有关于`xlsm`的内容。 - Srđan Popić
我认为他们现在已经删除了关于 xlsm 的那一部分,但仍然提到该文件类型得到支持。重要的是要明确设置 keep_vba 标志,因为它默认为 false。http://openpyxl.readthedocs.io/en/latest/usage.html?highlight=keep_vba - eule
2
该方法并不总是保持ActiveX组件(如按钮)与代码的连接。这可能与openpyxl中的按钮转换为图像的错误相同。 - Prof
显示剩余2条评论

9
我不知道这是否仍然与提问者有关,但我也遇到了同样的问题,并找到了一种可能的解决方案。
  1. 打开原始文件(比如:1.xlsm)并使用openpyxl进行操作;
  2. 另存为2.xlsx
  3. 两个文件实际上都是压缩文件:将它们提取到临时目录中;
  4. 从原始文件目录中复制文件到xlsx文件目录中:其中一个文件是宏(vbaProject.bin),还有两个文件是必需的,因为它们描述了文件类型等信息;
  5. 将属于xlsx目录的所有文件放回到一个zip文件中,并将其从zip重命名为xlsm。此文件包含原始宏,并已使用openpyxl进行编辑;
  6. (可选)删除两个临时目录和2.xlsx文件。
示例代码:
import openpyxl
import zipfile
from shutil import copyfile
from shutil import rmtree
import os

PAD = os.getcwd()

wb = openpyxl.load_workbook('1.xlsm')

#####
# do magic with openpyxl here and save
ws = wb.worksheets[0]
ws.cell(row=2, column=3).value = 'Edited'   # example
#####

wb.save('2.xlsx')


with zipfile.ZipFile('1.xlsm', 'r') as z:
    z.extractall('./xlsm/')

with zipfile.ZipFile('2.xlsx', 'r') as z:
    z.extractall('./xlsx/')

copyfile('./xlsm/[Content_Types].xml','./xlsx/[Content_Types].xml')
copyfile('./xlsm/xl/_rels/workbook.xml.rels','./xlsx/xl/_rels/workbook.xml.rels')
copyfile('./xlsm/xl/vbaProject.bin','./xlsx/xl/vbaProject.bin')

z = zipfile.ZipFile('2.zip', 'w')

os.chdir('./xlsx')

for root, dirs, files in os.walk('./'):
        for file in files:
            z.write(os.path.join(root, file))
z.close()

#clean
os.chdir(PAD)
rmtree('./xlsm/')
rmtree('./xlsx/')
os.remove('./2.xlsx')
os.rename('2.zip', '2.xlsm')

1
这个解决方案是我找到的最接近的,但是仍然存在一些文件错误,Excel在恢复过程中(有时候不总是)会弄乱宏! - Srđan Popić

6

在使用openpyxl编辑xlsm文件时,我遇到了同样的问题。我尝试了stackoverflow和其他论坛上提供的大部分解决方案/变通方法,但都没有奏效。后来我发现了xlwings这个Python库,它可以处理xlsm文档,并保留所有宏。

import xlwings as xw
wb = xw.Book('macro_xl.xlsm')
sheet = wb.sheets['Sheet1']
sheet.range('A1').value = 'From Script'
wb.save('result_file_name.xlsm')

错误:TypeError:'Book'对象不可订阅 - Vineesh TP
它对我起作用了。如果上述方法没有成功,请尝试这个 - im_infamous
值得注意的是,这可能是一个不错的解决方案,但在Linux上无法使用,因为XLWings在那里无法工作。 - T. Shaffner
@T.Shaffner 是的...它需要安装Excel(而Linux上没有Excel)。 - Jean-Francois T.
谢谢,谢谢,谢谢!非常有用的程序,适用于在Excel中处理大量工作的情况。 - king_anton

2
没错,openpyxl无法读取和编写VBA代码。
根据这个帖子

我认为你不应该给xlsM扩展名,因为文件中将不包含VBA代码。openpyxl仅用于构建xlsX文件。

相反,尝试使用这个分支:如果向load_workbook传递keep_vba=True参数,则应该可以完成工作。
希望能有所帮助。

2
对我没用。这是我使用的代码:wb = load_workbook('template.xlsm', keep_vba = True); - AnujAroshA
1
如果这个分支无法工作,那么使用 openpyxl 也无法使其工作。 - alecxe
找不到那个分支,但是可以在 https://bitbucket.org/amorris/editpyxl/src/master/ 找到。 - rleir

0

使用xlwings处理xlsm文档更好。我已经测试过了。

导入xlwings as xw

wb = xw.Book(DATA.xlsm)


0

如果您的初始Excel是使用Python创建的,则可能需要添加workbook.xml并解析sheet xlms:

for sheet in range(1,4):
    with open('sheetX.xml', 'r') as myfile: 'r') as myfile:
        my_str=myfile.read()

substr = "<dimension ref="
inserttxt = "<sheetPr codeName=\"Sheet"+str(sheet)+"\"/>"

idx = my_str.index(substr)
my_str = my_str[:idx] + inserttxt + my_str[idx:]

with open('sheetX.xml', "w") as text_file:
    text_file.write(my_str)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接