【问题标题】:How to save XLSM file with Macro, using openpyxl如何使用 openpyxl 使用宏保存 XLSM 文件
【发布时间】:2013-07-16 11:50:03
【问题描述】:

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

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

wb.save('testsave.xlsm');

但如果我按上述方式保存,我将无法打开该文件。但是如果我将它保存为 .xlsx 则我可以在没有原始文件的宏功能的情况下打开文件。

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

【问题讨论】:

    标签: python openpyxl xlsm


    【解决方案1】:

    对我来说,这与版本 openpyxl==2.3.0-b2 一起工作

    wb = load_workbook(filename='original.xlsm', read_only=False, keep_vba=True)
    ..
    wb.save('outfile.xlsm')
    

    这里的文档中也提到了:http://openpyxl.readthedocs.org/en/latest/usage.html?highlight=keep_vba#write-a-workbook-from-xltm-as-xlsm

    【讨论】:

    • 之后是否可以从python调用和运行宏?
    • 如果您安装了 MS Office 并运行 Windows,那么您可以使用 OLE api 运行它。否则你必须在 Python 中使用 openpyxl 重新设计宏代码。
    • 此链接与xlsm 无关!事实上,如果你去openpyxl.readthedocs.io/en/latest/usage.html?highlight=xlsm你会看到,什么都没有突出,因为没有关于xlsm的任何东西。
    • 我认为他们现在删除了关于 xlsm 的部分,但仍然提到支持文件类型。重要似乎明确设置了keep_vba 标志,因为它默认为false。 openpyxl.readthedocs.io/en/latest/usage.html?highlight=keep_vba
    • 此方法并不总是保持 ActiveX 组件(如按钮)连接到代码。可能和openpyxl按钮转换成图片的bug一样。
    【解决方案2】:

    我不知道这是否仍然与提出问题的人相关,但我正在处理同样的问题并找到了可能的解决方案。

    1. 打开原始文件(例如:1.xlsm)并使用 openpyxl 变魔术;
    2. 另存为2.xlsx
    3. 这两个文件实际上都是压缩文件:将它们解压到一个临时目录;
    4. 将文件从原始文件目录复制到xlsx文件目录:其中一个文件是宏(vbaProject.bin),其中2个文件是必需的,因为它们描述了其中的文件类型其他事情;
    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')
    

    【讨论】:

    • 这个解决方案是我找到的最接近的解决方案,但我仍然在文件中遇到一些错误,excel 试图恢复。在此恢复期间,它(有时,并非总是)弄乱了宏!
    【解决方案3】:

    我在使用 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:“书”对象不可下标
    • 它对我有用。如果上述方法没有成功,请尝试this
    • 值得注意的是,这可能是一个很好的解决方案,但不适用于 Linux,因为 XLWings 在那里无法使用。
    【解决方案4】:

    没错,openpyxl不能读写VBA代码。

    根据this thread

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

    试一试this fork:如果您将keep_vba=True 参数传递给load_workbook,它应该可以完成这项工作。

    希望对您有所帮助。

    【讨论】:

    • 它对我不起作用。这是我的代码wb = load_workbook('template.xlsm', keep_vba = True);
    • 如果这个 fork 不起作用 - 那么,就无法使用 openpyxl 使其工作。
    • 找不到那个叉子但是有bitbucket.org/amorris/editpyxl/src/master
    【解决方案5】:

    如果您的初始 excel 是使用 python 创建的,您可能还需要添加 workbook.xml 并解析工作表 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)
    

    【讨论】:

      【解决方案6】:

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

      将 xlwings 导入为 xw

      wb = xw.Book(DATA.xlsm)

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-01-11
        • 2021-07-11
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多