我有一个宏,我想要使用一堆现有的电子表格。唯一的问题是,有太多的电子表格,手动操作太费时间了!
我已经编写了一个Python脚本来使用pyWin32访问所需的文件,但我似乎无法找到一种方法来使用它来添加宏。
这里有一个类似的问题给出了这个答案(它不是Python,但看起来它仍然使用COM),但我的COM对象似乎没有一个名为VBProject的成员:
Set objExcel = CreateObject("Excel.Application")
objExcel.Visible = True
objExcel.DisplayAlerts = False
Set objWorkbook = objExcel.Workbooks.Open("C:\scripts\test.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:\scripts\test.xls"
objExcel.Quit
编辑:链接到引用的类似问题:Inject and execute Excel VBA code into spreadsheet received from external source
我也忘了提到虽然这不是Python,但我希望通过COM对象可以使用类似的对象成员。
答案 0 :(得分:9)
这是转换后的代码。您可以使用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()
答案 1 :(得分:4)
由于我还有一段时间努力做到这一点,我将提供另一个应该使用Excel 2007/2010 / 2013 xlsm
格式的示例。与上面提供的示例没有太大区别,如果没有循环遍历不同的文件并且包含更多注释,它只是更简单一点。此外,宏的源代码是从文本文件加载而不是在Python脚本中硬编码。
请记住根据需要调整脚本顶部的文件路径。
此外,请记住Excel 2007/2010/2013仅允许以xlsm
格式存储包含宏的工作簿,而不是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
答案 2 :(得分:0)
@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)
答案 3 :(得分:0)
我想补充一点。我在尝试解析文件夹中的每个.xlsm文件时遇到了麻烦。我想出了如何使用glob并在for语句中格式化with语句的方法。我是编程新手,所以如果我使用的术语不正确,请原谅。希望这对其他人有帮助。谢谢。
import glob
import os, sys
import win32com.client
_file = os.path.abspath(sys.argv[0])
path = os.path.dirname(_file)
pathToMacro = path + r'\macro2.txt'
myMacroName = 'TestMacro'
for fname in glob.glob(path + "\*.xlsm"):
with open (pathToMacro, "r") as myfile:
print('reading macro into string from: ' + str(myfile))
macro=myfile.read()
excel = win32com.client.Dispatch("Excel.Application")
excel.Visible = False
workbook = excel.Workbooks.Open(Filename=fname)
excelModule = workbook.VBProject.VBComponents.Add(1)
excelModule.CodeModule.AddFromString(macro)
excel.Application.Run('Module1.CleanDataPivot')
excel.Workbooks(1).Close(SaveChanges=1)
excel.Application.Quit()
del excel
现在,我无需打开excel就可以对文件夹中的每个.xlsm文件运行一个宏。