使用 win32com 打开包含公式的 Excel 文件,添加一些延迟,并保存为 CSV

Use win32com to Open Excel file with formulas, add some delay, & save as CSV

我有一个 Excel 文件,里面有一堆公式。正确加载公式需要时间(~1-2 分钟),因此我试图在打开文件和保存加载文件之间添加一些延迟。完成此操作后,我希望将完全加载的 Excel 文件的副本另存为具有不同名称的新 CSV,以便我同时拥有完全加载的 Excel 文件和新的 CSV 文件.

明确地说,我正在尝试按此顺序执行以下任务:

  1. 打开 Excel 文件
  2. 添加一些延迟(约 1-2 分钟)
  3. 保存完全加载的 Excel 文件
  4. 将完全加载的 Excel 文件的副本另存为具有不同名称的 CSV

我已经成功完成了如下所示的第 1 步和第 3 步,但在执行第 2 步和第 4 步时遇到了问题。我注意到第 2 步非常重要,因为我现在编写代码的方式并不为公式加载留出足够的时间,从而导致文件加载不完整。

执行第 2 步和第 4 步的最佳方法是什么,即添加延迟,然后将整个文件另存为 CSV?

import win32com.client as win32

excel = win32.gencache.EnsureDispatch('Excel.Application')

#opens file denoted by PATH
workbook = excel.Workbooks.Open(PATH)

#saves file
workbook.Save()

#closes and quits Excel
workbook.Close()
excel.Quit()

请注意此代码基于 this post

您可以开始 Excel 计算,然后让您的 Python 代码等待:

import time

#...
workbook = excel.Workbooks.Open(PATH)
excel.CalculateFull() #If Calculation is set to Manual
#Wait 10 seconds
time.sleep(10)
workbook.Save()
#...

当然,你不知道10秒是太长还是太短。

更精确的方法是开始计算,然后等待 Excel 告诉您它已完成。 Excel Application 对象在完成计算树时发出 AfterCalculation 事件信号。您可以设置 Python 代码以等待此事件发出信号后再继续。

完整代码:

import win32com.client as wc
import pythoncom #From package pywin32
import win32api
import win32con
from os.path import join

#Class to handle the SyncObject events from Outlook
class CalcHandler(object): 
    def OnAfterCalculate(self):
        #Calculation has finished so send WM_QUIT to message loop
        win32api.PostThreadMessage(win32api.GetCurrentThreadId(), win32con.WM_QUIT, 0, 0)       
        print('... calculation complete')

#Get the application Dispatch interface
xl = wc.gencache.EnsureDispatch('Excel.Application')

path = 'path_to_directory'

#opens a file
workbook = xl.Workbooks.Open(join(path,'test.xlsx'))

if workbook is not None:
    #Create an event handler
    wc.WithEvents(xl,CalcHandler)

    print('Starting calculation ...')
    #Force a calcuation
    xl.CalculateFull()

    #This will block until a WM_QUIT message is sent to the message queue
    pythoncom.PumpMessages()

    #saves file as a CSV
    xl.DisplayAlerts=False
    workbook.SaveAs(join(path,'test.csv'),wc.constants.xlCSV)

    #closes and quits Excel
    workbook.Close()

if xl.Workbooks.Count == 0:
    xl.Quit()
    xl=None