Используйте Python для вставки макросов в электронные таблицы
У меня есть макрос, который я хотел бы использовать кучу существующих электронных таблиц. Единственная проблема заключается в том, что есть так много таблиц, что было бы слишком много времени, чтобы сделать это вручную!
Я написал скрипт Python для доступа к необходимым файлам с помощью pyWin32,но я не могу найти способ использовать его для добавления макроса.
аналогичный вопрос здесь дал этот ответ (это не Python, но похоже, что он все еще использует COM), но мой COM-объект, похоже, не имейте член под названием VBProject:
Set objExcel = CreateObject("Excel.Application")
objExcel.Visible = True
objExcel.DisplayAlerts = False
Set objWorkbook = objExcel.Workbooks.Open("C:scriptstest.xls")
Set xlmodule = objworkbook.VBProject.VBComponents.Add(1)
strCode = _
"sub test()" & vbCr & _
" msgbox ""Inside the macro"" " & vbCr & _
"end sub"
xlmodule.CodeModule.AddFromString strCode
objWorkbook.SaveAs "c:scriptstest.xls"
objExcel.Quit
EDIT: ссылка на аналогичный вопрос, на который ссылается:внедрить и выполнить код Excel VBA в электронную таблицу, полученную из внешнего источника
Я также забыл упомянуть, что, хотя это не Python, я надеялся, что подобные члены объекта будут доступны мне через COM-объекты.
3 ответов
это преобразованный код. Вы можете использовать win32com или comtypes пакеты.
import os
import sys
# Import System libraries
import glob
import random
import re
sys.coinit_flags = 0 # comtypes.COINIT_MULTITHREADED
# USE COMTYPES OR WIN32COM
#import comtypes
#from comtypes.client import CreateObject
# USE COMTYPES OR WIN32COM
import win32com
from win32com.client import Dispatch
scripts_dir = "C:\scripts"
conv_scripts_dir = "C:\converted_scripts"
strcode = \
'''
sub test()
msgbox "Inside the macro"
end sub
'''
#com_instance = CreateObject("Excel.Application", dynamic = True) # USING COMTYPES
com_instance = Dispatch("Excel.Application") # USING WIN32COM
com_instance.Visible = True
com_instance.DisplayAlerts = False
for script_file in glob.glob(os.path.join(scripts_dir, "*.xls")):
print "Processing: %s" % script_file
(file_path, file_name) = os.path.split(script_file)
objworkbook = com_instance.Workbooks.Open(script_file)
xlmodule = objworkbook.VBProject.VBComponents.Add(1)
xlmodule.CodeModule.AddFromString(strcode.strip())
objworkbook.SaveAs(os.path.join(conv_scripts_dir, file_name))
com_instance.Quit()
поскольку я также боролся некоторое время, чтобы получить это право, я приведу еще один пример, который должен работать с Excel 2007/2010/2013 в . Нет большой разницы в приведенном выше примере, это просто немного проще без цикла над различными файлами и с большим количеством комментариев. Кроме того, исходный код макроса загружается из текстового файла, а не жестко кодируется в скрипте Python.
не забудьте адаптировать пути к файлам вверху сценария к вашим потребностям.
кроме того, помните, что Excel 2007/2010/2013 позволяет хранить книги только с макросами в , не xlsx
. При вставке макроса в xlsx
файл, вам будет предложено сохранить его в другом формате или макрос не будет включен в файл.
и последнее, но не менее важное, убедитесь, что опция Excel для выполнения кода VBA извне приложения активирована (которая по умолчанию отключена для безопасности причинам), в противном случае вы получите сообщение об ошибке. Для этого откройте Excel и перейдите в
Файл - > Параметры - > Центр доверия - > настройки Центра доверия - > настройки макросов - > активировать флажок на Trust access to the VBA project object model
.
# necessary imports
import os, sys
import win32com.client
# get directory where the script is located
_file = os.path.abspath(sys.argv[0])
path = os.path.dirname(_file)
# set file paths and macro name accordingly - here we assume that the files are located in the same folder as the Python script
pathToExcelFile = path + '/myExcelFile.xlsm'
pathToMacro = path + '/myMacro.txt'
myMacroName = 'UsefulMacro'
# read the textfile holding the excel macro into a string
with open (pathToMacro, "r") as myfile:
print('reading macro into string from: ' + str(myfile))
macro=myfile.read()
# open up an instance of Excel with the win32com driver
excel = win32com.client.Dispatch("Excel.Application")
# do the operation in background without actually opening Excel
excel.Visible = False
# open the excel workbook from the specified file
workbook = excel.Workbooks.Open(Filename=pathToExcelFile)
# insert the macro-string into the excel file
excelModule = workbook.VBProject.VBComponents.Add(1)
excelModule.CodeModule.AddFromString(macro)
# run the macro
excel.Application.Run(myMacroName)
# save the workbook and close
excel.Workbooks(1).Close(SaveChanges=1)
excel.Application.Quit()
# garbage collection
del excel
то, что @Dirk и @dilbert упомянули, отлично работает. Вы также можете добавить этот фрагмент кода, который будет программно включать доступ к "объектному модулю VBA"
import win32api
import win32con
key = win32api.RegOpenKeyEx(win32con.HKEY_CURRENT_USER,
"Software\Microsoft\Office\16.0\Excel"
+ "\Security", 0, win32con.KEY_ALL_ACCESS)
win32api.RegSetValueEx(key, "AccessVBOM", 0, win32con.REG_DWORD, 1)