¿Ejecutando una macro de Excel a través de Python?

Estoy intentando ejecutar una macro a través de python, pero no estoy seguro de cómo hacer que funcione …

Tengo el siguiente código hasta ahora, pero no está funcionando.

import win32com.client xl=win32com.client.Dispatch("Excel.Application") xl.Workbooks.Open(Filename="C:\test.xlsm",ReadOnly=1) xl.Application.Run("macrohere") xl.Workbooks(1).Close(SaveChanges=0) xl.Application.Quit() xl=0 

Me sale el siguiente rastreo:

 Traceback (most recent call last): File "C:\test.py", line 4, in  xl.Application.Run("macrohere") File "<COMObject >", line 14, in Run File "C:\Python27\lib\site-packages\win32com\client\dynamic.py", line 282, in _ApplyTypes_ result = self._oleobj_.InvokeTypes(*(dispid, LCID, wFlags, retType, argTypes) + args) com_error: (-2147352567, 'Exception occurred.', (0, u'Microsoft Excel', u"Cannot run the macro 'macrohere'. The macro may not be available in this workbook or all macros may be disabled.", u'xlmain11.chm', 0, -2146827284), None) 

EDITAR

 import win32com.client xl=win32com.client.Dispatch("Excel.Application") xl.Workbooks.Open(Filename="C:\test.xlsm",ReadOnly=1) try: xl.Application.Run("test.xlsm!testmacro.testmacro") # It does run like this... but we get the following error: # Traceback (most recent call last): # File "C:\test.py", line 7, in  # xl.Workbooks(1).Close(SaveChanges=0) # File "C:\Python27\lib\site-packages\win32com\client\dynamic.py", line 192, in __call__ # return self._get_good_object_(self._oleobj_.Invoke(*allArgs),self._olerepr_.defaultDispatchName,None) # com_error: (-2147352567, 'Exception occurred.', (0, None, None, None, 0, -2147352565), None) except: # Except isn't catching the above error... :( xl.Workbooks(1).Close(SaveChanges=0) xl.Application.Quit() xl=0 

Espero que el error tenga que ver con la macro a la que está llamando, pruebe el siguiente código:

Código

 import os, os.path import win32com.client if os.path.exists("excelsheet.xlsm"): xl=win32com.client.Dispatch("Excel.Application") xl.Workbooks.Open(os.path.abspath("excelsheet.xlsm"), ReadOnly=1) xl.Application.Run("excelsheet.xlsm!modulename.macroname") ## xl.Application.Save() # if you want to save then uncomment this line and change delete the ", ReadOnly=1" part from the open function. xl.Application.Quit() # Comment this out if your excel script closes del xl 

Hice algunas modificaciones al código de SMNALLY para que pueda ejecutarse en Python 3.5.2. Este es mi resultado:

 #Import the following library to make use of the DispatchEx to run the macro import win32com.client as wincl def runMacro(): if os.path.exists("C:\\Users\\Dev\\Desktop\\Development\\completed_apps\\My_Macr_Generates_Data.xlsm"): # DispatchEx is required in the newest versions of Python. excel_macro = wincl.DispatchEx("Excel.application") excel_path = os.path.expanduser("C:\\Users\\Dev\\Desktop\\Development\\completed_apps\\My_Macr_Generates_Data.xlsm") workbook = excel_macro.Workbooks.Open(Filename = excel_path, ReadOnly =1) excel_macro.Application.Run\ ("ThisWorkbook.Template2G") #Save the results in case you have generated data workbook.Save() excel_macro.Application.Quit() del excel_macro 

Sospecho que no ha autorizado su instalación de Excel para ejecutar macro desde un Excel automatizado. Es una protección de seguridad por defecto en la instalación. Para cambiar esto:

  1. Archivo> Opciones> Centro de confianza
  2. Haga clic en el botón Configuración del Centro de Confianza …
  3. Configuración de macros> Marcar Habilitar todas las macros

Hmm, estaba teniendo problemas con esa parte (sí, todavía xD):

xl.Application.Run("excelsheet.xlsm!macroname.macroname")

porque no uso excel a menudo (lo mismo con vb o macros, pero necesito usar femap con python), así que finalmente lo resolví revisando la lista de macros: Desarrollador -> Macros: vi que: macroname.macroname debería ser sheet_name.macroname como en la lista de “macros”.

(Gasté algo como 30min-1h tratando de resolverlo, por lo que puede ser útil para los noobs como yo en Excel) xD

Probé el modo win32com y el modo xlwings pero no tuve suerte. Utilizo PyCharm y no veo la opción .WorkBook en el autocompletado para win32com. Recibí el error -2147352567 cuando intenté pasar un libro de trabajo como variable.

Luego, encontré una solución al uso del shell vba para ejecutar mi script de Python. Escriba algo en el archivo XLS con el que está trabajando cuando haya terminado. Para que Excel sepa que es hora de ejecutar la macro VBA.

Pero la función vba Application.wait ocupará el 100% de la CPU, lo que es extraño. Algunas personas dijeron que usar la función Sleep de Windows lo arreglaría.

  Import xlsxwriter Shell "C:\xxxxx\python.exe C:/Users/xxxxx/pythonscript.py" exitLoop = 0 

Espera a que Python termine su trabajo.

  Do waitTime = TimeSerial(Hour(Now), Minute(Now), Second(Now) + 30) Application.Wait waitTime Set wb2 = Workbooks.Open("D:\xxxxx.xlsx", ReadOnly:=True) exitLoop = wb2.Worksheets("blablabla").Cells(50, 1) wb2.Close exitLoop Loop While exitLoop <> 1 Call VbaScript 

Para Python 3.7 o posterior, (2018-10-10), tengo que combinar la respuesta de @Alejandro BR y SMNALLY, porque @Alejandro se olvida de definir wincl.

 import os, os.path import win32com.client if os.path.exists('C:/Users/jz/Desktop/test.xlsm'): excel_macro = win32com.client.DispatchEx("Excel.Application") # DispatchEx is required in the newest versions of Python. excel_path = os.path.expanduser('C:/Users/jz/Desktop/test.xlsm') workbook = excel_macro.Workbooks.Open(Filename = excel_path, ReadOnly =1) excel_macro.Application.Run("test.xlsm!Module1.Macro1") # update Module1 with your module, Macro1 with your macro workbook.Save() excel_macro.Application.Quit() del excel_macro 

Una variación en el código de SMNALLY que no cierra Excel si ya lo tiene abierto:

 import os, os.path import win32com.client if os.path.exists("excelsheet.xlsm"): xl=win32com.client.Dispatch("Excel.Application") wb = xl.Workbooks.Open(os.path.abspath("excelsheet.xlsm"), ReadOnly=1) #create a workbook object xl.Application.Run("excelsheet.xlsm!modulename.macroname") wb.Close(False) #close the work sheet object rather than quitting excel del wb del xl 

Sólo una nota rápida con un xlsm con espacios.

 file = 'file with spaces.xlsm' excel_macro.Application.Run('\'' + file + '\'' + "!Module1.Macro1")