在python代码中调用vba宏
工作以python为主体,但是遇到了一些word操作的需求(详见上一篇),这个需求用word自带的功能会很容易实现,于是就想着能不能用python调用宏来处理。
网上找了一圈,发现了一大堆方法(因为一个个都在我那诡异的工作环境下全失败了所以真的找了很多),给各位罗列一下。
本文使用win32com库。
①在文档中存入宏,直接调用。
import win32com
from win32com.client import Dispatch
def updateContent(url):
docApp = win32com.client.DispatchEx('Word.Application')
try:
doc = docApp.Documents.Open(url)
doc.Run('...宏名称,不用带括号...')
doc.Save()
print("宏运行成功")
except Exception as e:
print(e)
#保证即使出错也能关掉窗口,否则后台会出现大量word进程且可能占用文件
docApp.Quit()
if __name__ == "__main__":
updateContent("D:/testdocx.docm")
x = input()
遇到的问题:很显然,这需要文档中本来就有宏,而且必须得保存为docm格式。而且对于一个新文件,设置不当的话还得打开一下确定启用宏(即使开了低安全度视软件版本也有这个可能)。
②变体1:保存为docx格式
前略,try:
doc = docApp.Documents.Open('原始url.docm')
doc.Run('宏名称,不用带括号')
docApp.DisplayAlerts = False
doc.SaveAs('另一个url.docx')
print("宏运行成功")
except Exception as e: 后略。
如上所述。excel似乎需要更多类似DisplayAlerts = False的操作,但word只需要改变这一项即可不保存宏。
③变体2:从别的文件中调用宏
前略,try:
doc = docApp.Documents.Open('原始url.docx')
doc.Run('带宏文件url.docm!里面的一个宏名')
doc.Save()
print("宏运行成功")
except Exception as e: 后略。
“!”符号使你能指定将另一个文件中的宏在本文件中运行。
两个变体的问题:
两个变体都涉及到了对复数文件的操作。这在我的电脑上是没有问题的,但是在实际工作用的电脑上一直报错pywintypes.com_error:(-2147352567,‘发生意外。’,(0,None,None,None,0,-2147024891),None)。
网上对这个问题的说明是文件占用(打开着),但是我很确信没有。排查测试的结果是只要只涉及一个文件必不报错,涉及多个文件必报错。
不知道是那台电脑上只有wps的原因还是纯内网+云电脑的环境有什么奇怪的设置。(我甚至报过’RPC服务器不可用’,完全不能理解为什么,明明好好地开着)
④为什么我之前没有搜到直接写代码的?
这是我使用的宏代码:(作用是更新目录且只更新页码,见上一篇文章)
Sub UpdateContent()
Dim aStory As Range
Dim aField As Field
For Each aStory In ActiveDocument.StoryRanges
For Each aField In aStory.Fields
if aField.Type == 37:
aField.Update
Next aField
Next aStory
End Sub
这是我最后实际使用的python代码:
import win32com
from win32com.client import Dispatch
def updateContent(url):
docApp = win32com.client.DispatchEx('Word.Application')
try:
doc = docApp.Documents.Open(url)
for aRange in doc.StoryRanges:
for aField in aRange.Fields:
if aField.Type == 37:
aField.Update()
doc.Save()
print("目录更新成功")
except Exception as e:
print(e)
#保证即使出错也能关掉窗口,否则后台会出现大量word进程且可能占用文件
docApp.Quit()
if __name__ == "__main__":
updateContent("D:/testdocx.docx")
x = input()
是的,这就是巨硬的兼容力。直接用就完事了。没有文件问题,没有docxdocm的格式问题,甚至不需要“启用宏”。我浪费的一整天的时间究竟是……
根据MSDN的文档,VB整体都.net化了。所以基本都是可以直接用的。
!!!注意:!!!
python并不在.net文档列明的支持语言中,所以并不一定可以使用所有vb代码。但至少本文所涉的没有问题。建议各位具体使用时尝试一下,不行的话就用方法123,毕竟正常的电脑上是不该出现我遇到的问题的。