2013-06-19 20 views
12

Ho una macro che mi piacerebbe utilizzare un mucchio di fogli di lavoro esistenti. L'unico problema è che ci sono così tanti fogli di calcolo che sarebbe troppo dispendioso in termini di tempo per farlo a mano!Utilizzare Python per iniettare macro in fogli di calcolo

ho scritto uno script Python per accedere ai file necessari utilizzando pyWin32, ma io non riesco a capire un modo di usarlo per aggiungere la macro in.

Una domanda simile qui ha dato questa risposta (non è Python, ma sembra che utilizza ancora COM), ma il mio oggetto COM non sembra avere un membro chiamato 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 

EDIT: link alla domanda simile si fa riferimento: Inject and execute Excel VBA code into spreadsheet received from external source

Ho anche dimenticato di menzionare questo anche se questo non è Python, speravo che membri di oggetti simili fossero disponibili per me tramite gli oggetti COM.

+0

"Una domanda simile qui ha dato questa risposta" Un collegamento manca qui, non è vero? –

+2

Bene, per iniziare, il codice di esempio non è nemmeno Python; Sono abbastanza sicuro che sia Visual Basic. –

+1

Ho modificato la mia domanda! –

risposta

7

Questo è il codice convertito. È possibile utilizzare i pacchetti win32com o 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() 
+0

Grazie per l'aiuto! Per essere esauriente, ho dovuto anche spuntare l'opzione "Accesso sicuro al modulo dell'oggetto progetto VBA" in "Opzioni di Excel" -> scheda "Centro protezione" -> "Impostazioni Centro protezione ..." -> scheda Impostazioni macro su essere in grado di eseguire questo codice. –

3

Come ho anche faticato un po 'di tempo per ottenere questo diritto, fornirò un altro esempio che si suppone di lavorare con Excel/2010/2013 di formato 2007 xlsm. Non c'è molta differenza nell'esempio sopra riportato, è solo un po 'più semplice senza il loop su diversi file e con più commenti inclusi. Inoltre, il codice sorgente della macro viene caricato da un file di testo invece di codificarlo con hard disk nello script Python.

Ricordarsi di adattare i percorsi dei file nella parte superiore dello script alle proprie esigenze.

Inoltre, ricordare che Excel 2007/2010/2013 consente solo di memorizzare cartelle di lavoro con macro nel formato xlsm, non in xlsx. Quando si inserisce una macro in un file xlsx, verrà richiesto di salvarlo in un formato diverso o la macro non verrà inclusa nel file.

E, ultimo ma non meno importante, verificare che l'opzione di Excel per l'esecuzione del codice VBA dall'esterno dell'applicazione sia attivata (che è disattivata per impostazione predefinita per motivi di sicurezza), in caso contrario verrà visualizzato un messaggio di errore. Per fare ciò, apri Excel e vai su

File -> Opzioni -> Centro protezione -> Impostazioni Centro protezione -> Impostazioni macro -> attiva il segno di spunta su Trust access to the VBA project object model.

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

# necessary imports 
import os, sys 
import win32com.client 

# 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