使用Python更新Excel电子表格中的链接

我正在Python中运行模拟,生成输出,需要由他们的Excel工作簿中的build模人员直接使用。 我生成的代码将直接输出我的数据到他们的Excel电子表格模板。 我已经生成的代码直接输出到他们的模板的代码是好的,但我遇到的问题是,build模者有一系列的“链接”在一起的工作簿。 如果我将数据插入到电子表格中,除非用户以“编辑链接” – >“更新值”的forms打开工作簿,否则指向该工作簿的链接不会更新。 如果有一个工作簿,那么用户可以简单地打开工作簿,没有问题。 实际上,将会有100多个工作簿需要更新链接。 不幸的是,我没有办法改变build模人员链接工作簿的方法 – 我唯一能做的就是调整他们的方法。

我的目标是创build一个Python解决scheme,允许我1)生成模拟数据,2)将我生成的数据插入到build模者的工作簿中,3)更新工作簿之间的所有链接。 最终,为了简化,我希望能够在一个端到端的Python程序中做所有的三个。 我已经解决了(1)和(2),并且我对(3)的解决scheme几乎可行。 我已经生成了以下function脚本:

from win32com.client import Dispatch import pandas as pd from openpyxl import load_workbook import os import time def run_macro(workbook_name, vba_sub, com_instance): wb = com_instance.workbooks.open(workbook_name) wb.RefreshAll() xl_module = wb.VBProject.VBComponents.Add(1) xl_module.CodeModule.AddFromString(vba_sub.strip()) com_instance.Application.Run('UpdateLinkValues') wb.Save() wb.Close() return True def main(): dir_root = ("C:\\Model_Spreadsheets") vba_sub = \ ''' sub UpdateLinkValues() Application.AskToUpdateLinks = False ActiveWorkbook.UpdateLink Name:=ActiveWorkbook.LinkSources end sub ''' xl_app = Dispatch("Excel.Application") xl_app.Visible = False xl_app.DisplayAlerts = False for root, dirs, files in os.walk(dir_root): for fn in files: if fn.endswith(".xlsx") and fn[0] is not "~": run_macro(os.path.join(root, fn), vba_sub, xl_app) xl_app.Quit() if __name__ == "__main__": main() 

这个脚本非常接近我正在寻找的正确解决scheme,但是我似乎“随机”地遇到了一个VBA错误:

 run-time error '1004' method 'updatelink' method of object '_workbook' failed 

每次尝试运行此脚本时,都会出现此错误,但每次都不会出现在同一个工作簿中 – 有时会出现在第一个工作簿中,有时在第15个等等。

我有一个在VBA中进行debugging的选项,而且我可以继续到下一个工作簿的唯一方法是如果将macros更改为

 sub UpdateLinkValues() Application.AskToUpdateLinks = False end sub 

如果我运行这个macros并退出debugging,程序将继续运行,直到再次遇到相同的错误。 我的第一个想法是,在打开工作簿并尝试运行macros之间可能存在计时问题。 我find的解决方法是我可以更改macros和应用程序的可见性:

 vba_sub = \ ''' sub UpdateLinkValues() Application.AskToUpdateLinks = False end sub ''' 

 xl_app.Visible = True 

这工作正常,但我不是每个工作簿打开和closures,因为它需要很长时间的粉丝。 我的问题是,有没有人知道为什么这个运行时错误即将到来 – 一个解决scheme? 或者也许,有没有人知道如何拦截在Python运行时错误作为例外? 如果我可以截取这个错误作为python的exception,那么我可以使用我的替代解决scheme的特定工作簿。

提前致谢!

考虑让Python直接运行方法UpdateLink与你初始化的COM对象,即xl_appwb对象。 不需要在每个工作簿中创build一个macros,然后调用它。

如果工作簿没有链接,则在UpdateLink()下方封装try/except/finally块,因为LinkSources将返回一个值,引发COMexception,您收到的错误:

对象“_workbook”的运行时错误“1004”方法“updatelink”方法失败

另外,请确保在初始化对象(在VBA中也是一个很好的最佳实践: Set wb = Nothing )以释放CPU资源,否则它们将保留为后台进程,直到垃圾收集为止。

 def run_macro(workbook_name, com_instance): wb = com_instance.workbooks.open(workbook_name) com_instance.AskToUpdateLinks = False try: wb.UpdateLink(Name=wb.LinkSources()) except Exception as e: print(e) finally: wb.Close(True) wb = None return True def main(): dir_root = ("C:\\Model_Spreadsheets") xl_app = Dispatch("Excel.Application") xl_app.Visible = False xl_app.DisplayAlerts = False for root, dirs, files in os.walk(dir_root): for fn in files: if fn.endswith(".xlsx") and fn[0] is not "~": run_macro(os.path.join(root, fn), xl_app) xl_app.Quit() xl = None 

另外,虽然VBA默认使用Excel和MS Office应用程序,但它实际上是一个独立的组件。 要检查,在VBA IDE的Tools \ References下,你会看到VBA是第一个选中的项目,没有任何内build的。 事实上,VBA完全是在Python中做的:制作一个到Excel对象库的COM接口。 所以在某种意义上,VBA就像Excel和Python一样。