Python通过COM对象加载Excel后公式与Bloomberg数据无法刷新
解决Win32加载Excel时Bloomberg API公式无法刷新的问题
我最近在用Python的win32com库加载一个带Bloomberg Excel API公式的xlsm文件,遇到了个棘手的问题:手动打开表格时,17-65列里的BDP函数(比如=BDP(E9&" corp","CRNCY"))和除法公式都能正常刷新出正确值,但用代码加载后,这些公式驱动列要么显示0,要么是N/A。我试了启用计算、调用各种Calculate方法都没用,下面是我的相关代码:
import win32com.client as win32 def open_workbook(xlapp, xlfile, password=None): try: xlwb = xlapp.Workbooks("LAP.xlsm") except Exception as e: print("No 1. Error: ", e) try: xlwb = xlapp.Workbooks.Open(xlfile, Password=password, UpdateLinks=0) except Exception as e: print(e) xlwb = None return xlwb def main(file, password=None): xlapp = win32.gencache.EnsureDispatch("Excel.Application") xlapp.DisplayAlerts = True xlapp.Visible = True print(check.check_file(file, xlapp)) if not check.check_file(file, xlapp): xlwb = open_workbook(xlapp, xlfile=file, password=password) else: print("Error") # TODO 若无法打开文件该如何处理:重试、提示用户?... # Resources工作表包含Data工作表公式所用的货币汇率 res = xlwb.Sheets('Resources') # 以下Calculate相关操作是我尝试修复问题的手段 res.EnableCalculation = False res.EnableCalculation = True res.Calculate() # 这是后续要加载到Pandas DataFrame的目标主工作表 xlws = xlwb.Sheets('Data') last_col = xlws.UsedRange.Columns.Count last_row = xlws.UsedRange.Rows.Count # 所有这些Calculate操作尝试修复问题,但均无效 xlws.EnableCalculation = False xlws.EnableCalculation = True xlws.Calculate() xlws.Columns(17).Calculate() xlws.Columns(16).Calculate() xlws.Columns(18).Calculate() xlws.Range(xlws.Cells(8,17), xlws.Cells(last_row,17)).Formula = \ xlws.Range(xlws.Cells(8,17),xlws.Cells(last_row,17)).Formula # 此内容将被加载到DataFrame content = xlws.Range(xlws.Cells(8,1), xlws.Cells(last_row, last_col)).Value print(len(content), type(content)) print(content[:10])
可能的解决方案及代码调整
针对Bloomberg API这类第三方插件的公式刷新问题,Excel自带的计算方法往往不够,需要针对性处理:
强制加载Bloomberg Excel插件
手动打开Excel时插件会自动加载,但win32com启动的Excel实例可能默认不加载,需要先确保插件启用:# 在创建xlapp实例后添加 bloomberg_addin = xlapp.AddIns("Bloomberg Excel Tools") if not bloomberg_addin.Installed: bloomberg_addin.Installed = True切换Excel计算模式为自动并等待刷新
有些情况下Excel实例的计算模式会被设为手动,先切换为自动,并且给Bloomberg API足够的刷新时间:# 设置计算模式为自动 xlapp.Calculation = win32.constants.xlCalculationAutomatic # 调用Bloomberg专属的刷新宏(插件内置功能) xlapp.Run("RefreshAllStaticData") # 等待15秒让数据完成刷新(时间可根据数据量调整) xlapp.Wait(xlapp.Now + win32.client.Variant(win32.client.constants.xlTime, 15)) # 最后触发一次全表计算 xlwb.CalculateFull()调整工作簿刷新设置
确保工作簿允许外部数据刷新,并且禁用后台刷新(避免数据还没刷完就读取):# 禁用后台查询,确保数据刷新完成后再继续 for conn in xlwb.Connections: if hasattr(conn, 'OLEDBConnection'): conn.OLEDBConnection.BackgroundQuery = False # 刷新所有外部数据连接 xlwb.RefreshAll() # 等待异步查询完成 xlapp.CalculateUntilAsyncQueriesDone()
调整后的main函数核心片段
把这些修复逻辑整合到你的代码里,比如在获取xlws之后添加:
# 加载Bloomberg插件 bloomberg_addin = xlapp.AddIns("Bloomberg Excel Tools") if not bloomberg_addin.Installed: bloomberg_addin.Installed = True # 配置计算和刷新 xlapp.Calculation = win32.constants.xlCalculationAutomatic # 禁用后台查询 for conn in xlwb.Connections: if hasattr(conn, 'OLEDBConnection'): conn.OLEDBConnection.BackgroundQuery = False # 刷新所有数据 xlwb.RefreshAll() # 调用Bloomberg刷新宏 xlapp.Run("RefreshAllStaticData") # 等待异步查询完成 xlapp.CalculateUntilAsyncQueriesDone() # 额外等待几秒确保Bloomberg数据加载完成 xlapp.Wait(xlapp.Now + win32.client.Variant(win32.client.constants.xlTime, 10)) # 全表计算 xlwb.CalculateFull() # 再读取数据 content = xlws.Range(xlws.Cells(8,1), xlws.Cells(last_row, last_col)).Value
注意事项
- 确保你的机器上已经安装了Bloomberg Excel插件,并且正常登录了Bloomberg终端(否则BDP函数无法获取数据)。
- 如果等待时间不够,可能还是会出现N/A,可以根据数据量适当延长等待时间。
- 有些情况下,Excel的信任中心设置会阻止插件在自动化环境中运行,需要在Excel的选项里把Bloomberg插件设为信任的加载项。
内容的提问来源于stack exchange,提问作者GXZ9




