web-dev-qa-db-fra.com

Vous exécutez une macro Excel via Python?

J'essaie de lancer une macro via Python mais je ne sais pas comment le faire fonctionner ...

J'ai le code suivant jusqu'à présent, mais ça ne marche pas.

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

Je reçois le suivi suivant:

Traceback (most recent call last):
  File "C:\test.py", line 4, in <module>
    xl.Application.Run("macrohere")
  File "<COMObject <unknown>>", 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)

MODIFIER

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 <module>
        # 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
30
Ryflex

Je m'attendrais à ce que l'erreur concerne la macro que vous appelez, essayez le code suivant:

Code

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
42
SMNALLY

J'ai apporté quelques modifications au code de SMNALLY afin qu'il puisse fonctionner sous Python 3.5.2. Ceci est mon résultat: 

#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
3
Alejandro BR

Je suppose que vous n’avez pas autorisé votre installation Excel à exécuter une macro à partir d’un Excel automatisé. C'est une protection de sécurité par défaut lors de l'installation. Pour changer cela:

  1. Fichier> Options> Centre de gestion de la confidentialité
  2. Cliquez sur le bouton Paramètres du centre de confiance ...
  3. Paramètres de la macro> Activer toutes les macros
2
Boud

Pour Python version 3.7 ou ultérieure (2018-10-10), je dois combiner les réponses de @Alejandro BR et SMNALLY, coz @Alejandro oublient de définir 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
0
PyBoss

Une variante du code de SMNALLY qui ne ferme pas Excel si vous l'avez déjà ouvert:

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
0
Peter Mabbott

J'ai essayé les méthodes win32com et xlwings mais je n'ai pas eu de chance. J'utilise PyCharm et je n'ai pas vu l'option .WorkBook dans l'auto-complétion pour win32com . J'ai eu l'erreur -2147352567 lorsque j'ai essayé de passer un classeur en tant que variable.

Ensuite, j'ai trouvé un moyen de contourner vba Shell pour exécuter mon script Python . Ecrivez quelque chose sur le fichier XLS que vous utilisez lorsque tout est terminé. Ainsi, Excel sait qu'il est temps d'exécuter la macro VBA.

Mais la fonction vba Application.wait prendra 100% du processeur, ce qui est bizarre. Certaines personnes ont dit que l’utilisation de la fonction Windows Sleep permettrait de le réparer.

 Import xlsxwriter


 Shell "C:\xxxxx\python.exe 
 C:/Users/xxxxx/pythonscript.py"

 exitLoop = 0

attendre que Python termine son travail.

  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
0
William Tong

Juste une note rapide avec un xlsm avec des espaces. 

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