簡體   English   中英

使用 Python 更新 Excel 電子表格中的鏈接

[英]Update Links in for Excel Spreadsheet Using Python

我正在 Python 中運行模擬,生成的輸出需要由建模者在其 excel 工作簿中直接使用。 我已經生成了將我的數據直接輸出到他們的 excel 電子表格模板中的代碼。 我生成的用於將數據直接輸出到他們的模板的代碼很好,但我遇到的問題是建模者有一系列“鏈接”在一起的工作簿。 如果我將數據插入到他們的電子表格中,則指向該工作簿的鏈接不會更新,除非用戶實際打開工作簿以“編輯鏈接”->“更新值”。 如果只有一個工作簿,則用戶可以毫無問題地打開該工作簿。 實際上,將有 100 多個工作簿需要更新鏈接。 不幸的是,我無法改變建模者鏈接工作簿的方法——我唯一能做的就是適應他們的方法。

我的目標是創建一個 Python 解決方案,使我能夠 1) 生成模擬數據,2) 將生成的數據插入建模者的工作簿,以及 3) 更新工作簿之間的所有鏈接。 最終,為了精簡,我希望能夠在一個端到端的 python 程序中完成所有三項工作。 我已經解決了 (1) 和 (2),並且我有一個幾乎有效的 (3) 解決方案。 我生成了以下功能腳本:

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()

該腳本非常接近我正在尋找的正確解決方案,但我似乎“隨機”遇到了 VBA 錯誤:

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

每次我嘗試運行這個腳本時都會出現這個錯誤,但它不會每次都出現在同一個工作簿上——有時,它出現在第一個工作簿上,有時出現在 15 日,等等......

我可以選擇在 VBA 中進行調試,我可以繼續處理下一個工作簿的唯一方法是將宏更改為

sub UpdateLinkValues()
    Application.AskToUpdateLinks = False
end sub

如果我運行這個宏並退出調試,程序將繼續運行,直到再次遇到相同的錯誤。 我的第一個想法是,在我打開工作簿和嘗試運行宏之間可能存在時間問題。 我發現的一種解決方法是我可以更改宏和應用程序可見性:

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

xl_app.Visible = True

這工作正常,但我不喜歡打開和關閉每個工作簿,因為這需要很長時間。 我的問題是,有誰知道為什么會出現這個運行時錯誤——有解決方案嗎? 或者,有沒有人知道如何將 Python 中的這個運行時錯誤作為異常攔截? 如果我可以將此錯誤作為 python 中的異常攔截,那么我可以使用我的替代解決方案來處理這些細節工作簿。

提前致謝!

考慮讓 Python 使用您初始化的 COM 對象(即xl_appwb對象)直接運行UpdateLink方法。 無需在每個工作簿中構建宏然后調用它。

UpdateLink()下面包含在try/except/finally塊中,以防工作簿沒有鏈接,因為LinkSources將返回一個Empty值,引發 COM 異常,即您收到的錯誤:

對象“_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 是第一個檢查的項目,沒有內置。 事實上,VBA 所做的正是您在 Python 中所做的:為 Excel 對象庫創建一個 COM 接口。 所以在某種意義上,VBA 與 Excel 和 Python 的關系一樣!

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM