Как сохранить файл XLSM с помощью Macro, используя openpyxl

У меня есть файл .xlsm с функцией Macro. Я загружаю его с помощью openpyxl и записываю некоторые данные в файл и, наконец, хочу сохранить его в другом файле .xlsm.

Чтобы сохранить файл как файл XLSM, я использовал приведенный ниже код в своем скрипте Python.

wb.save('testsave.xlsm');

Но я не могу открыть этот файл, если я сохранил, как указано выше. Но если я сохранил его как .xlsx, то я могу открыть файл без функции макроса, которую имел оригинальный файл.

Я хочу открыть лист Excel с функцией Macro, отредактировать файл и сохранить его как новый файл .xlsm, используя openpyxl. Как я могу это сделать?

3 ответа

Для меня это сработало вместе с версией 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

Не знаю, актуально ли это для того, кто задал вопрос, но я имею дело с той же проблемой и нашел возможное решение.

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')

У меня была такая же проблема при редактировании файлов xlsm с использованием openpyxl. Я испробовал большинство решений / обходных путей, доступных в stackru и на других форумах. Но никто из них не работал. Затем я нашел 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')

Правильно, openpyxl не может читать и писать код VBA.

По этой теме:

Я думаю, что вы не должны давать расширение xlsM, потому что файл не будет содержать код VBA. openpyxl используется только для сборки файлов xlsX.

Попробуйте вместо этого эту вилку: если вы пройдете keep_vba=True параметр для load_workbook это должно сделать работу.

Надеюсь, это поможет.

Если ваш исходный файл 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)

Для работы с xlsm документами лучше использовать xlwings. Я это проверил.

импортировать xlwings как xw

wb = xw.Book(DATA.xlsm)

Другие вопросы по тегам