千家信息网

如何使用Python子进程关闭Excel自动化中的弹窗

发表于:2025-11-18 作者:千家信息网编辑
千家信息网最后更新 2025年11月18日,本篇文章为大家展示了如何使用Python子进程关闭Excel自动化中的弹窗,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。利用Python进行Excel自动化操
千家信息网最后更新 2025年11月18日如何使用Python子进程关闭Excel自动化中的弹窗

本篇文章为大家展示了如何使用Python子进程关闭Excel自动化中的弹窗,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。

利用Python进行Excel自动化操作的过程中,尤其是涉及VBA时,可能遇到消息框/弹窗(MsgBox)。此时需要人为响应,否则代码卡死直至超时 [^1] [^2]。根本的解决方法是VBA代码中不要出现类似弹窗,但有时我们无权修改被操作的Excel文件,例如这是我们进行自动化测试的对象。所以本文记录从代码角度解决此类问题的方法。

假想场景

使用xlwings(或者其他自动化库)打开Excel文件test.xlsm,读取Sheet1!A1单元格内容。很简单的一个操作:

import xlwings as xw  wb = xw.Book('test.xlsm')  msg = wb.sheets('Sheet1').range('A1').value  print(msg)  wb.close()

然而不幸的是,打开工作簿时进行了热情的欢迎仪式:

Private Sub Workbook_Open()      MsgBox "Welcome"      MsgBox "to open"      MsgBox "this file."  End Sub

第一个弹窗Welcome就卡住了Excel,Python代码相应卡死在第一行。

基本思路

主程序中不可能直接处理或者绕过此类问题,也不能奢望有人随时蹲守点击下一步——那就开启一个子线程来护航吧。因此,解决方案是利用子线程监听并随时关闭弹窗,直到主程序圆满结束。

解决这个问题,需要以下两个知识点(基础知识请课外学习):

  • Python多线程(本文采用threading.Thread)

  • Python界面自动化库(本文涉及pywinauto和pywin32)

pywinauto方案

pywinauto顾名思义是Windows界面自动化库,模拟鼠标和键盘操作窗体和控件 [^3]。不同于先获取句柄再获取属性的传统方式,pywinauto的API更加友好和pythonic。例如,两行代码搞定窗口捕捉和点击:

from pywinauto.application import Application  win = Application(backend="win32").connect(title='Microsoft Excel')  win.Dialog.Button.click()

本文采用自定义线程类的方式,启动线程后自动执行run()函数来完成上述操作。具体代码如下,注意构造函数中的两个参数:

  • title 需要捕捉的弹窗的标题,例如Excel默认弹窗的标题为Microsoft Excel

  • interval 监听的频率,即每隔多少秒检查一次

# listener.py  import time  from threading import Thread, Event  from pywinauto.application import Application  class MsgBoxListener(Thread):      def __init__(self, title:str, interval:int):          Thread.__init__(self)          self._title = title           self._interval = interval           self._stop_event = Event()         def stop(self): self._stop_event.set()      @property      def is_running(self): return not self._stop_event.is_set()      def run(self):          while self.is_running:              try:                  time.sleep(self._interval)                  self._close_msgbox()              except Exception as e:                  print(e, flush=True)      def _close_msgbox(self):          '''Close the default Excel MsgBox with title "Microsoft Excel".'''                 win = Application(backend="win32").connect(title=self._title)          win.Dialog.Button.click()  if __name__=='__main__':     t = MsgBoxListener('Microsoft Excel', 3)      t.start()      time.sleep(10)      t.stop()

于是,整个过程分为三步:

  • 启动子线程监听弹窗

  • 主线程中打开Excel开始自动化操作

  • 关闭子线程

import xlwings as xw  from listener import MsgBoxListener  # start listen thread  listener = MsgBoxListener('Microsoft Excel', 3)  listener.start()  # main process as before  wb = xw.Book('test.xlsm')  msg = wb.sheets('Sheet1').range('A1').value  print(msg)  wb.close()  # stop listener thread  listener.stop()

到此问题基本解决,本地运行效果完全达到预期。但我的真实需求是以系统服务方式在服务器上进行Excel文件自动化测试,后续发现,当以系统服务方式运行时,pywinauto竟然捕捉不到弹窗!这或许是pywinauto一个潜在的问题 [^4]。

win32gui方案

那就只好转向相对底层的win32gui,所幸完美解决了上述问题。

win32gui是pywin32库的一部分,所以实际安装命令是:

pip install pywin32

整个方案和前文描述完全一致,只是替换MsgBoxListener类中关闭弹窗的方法:

import win32gui, win32con  def _close_msgbox(self):      # find the top window by title      hwnd = win32gui.FindWindow(None, self._title)      if not hwnd: return      # find child button      h_btn = win32gui.FindWindowEx(hwnd, None,'Button', None)      if not h_btn: return      # show text      text = win32gui.GetWindowText(h_btn)     print(text)      # click button             win32gui.PostMessage(h_btn, win32con.WM_LBUTTONDOWN, None, None)      time.sleep(0.2)      win32gui.PostMessage(h_btn, win32con.WM_LBUTTONUP, None, None)      time.sleep(0.2)

更一般的方案

更一般地,当同时存在默认标题和自定义标题的弹窗时,就不便于采用标题方式进行捕捉了。例如

MsgBox "Message with default title.", vbInformation,   MsgBox "Message with title My App 1", vbInformation, "My App 1"  MsgBox "Message with title My App 2", vbInformation, "My App 2"

那就扩大搜索范围,依次点击所有包含确定性描述的按钮(例如OK,Yes,Confirm)来关闭弹窗。同理替换MsgBoxListener类的_close_msgbox()方法(同时构造函数中不再需要title参数):

def _close_msgbox(self):     '''Click any button ("OK", "Yes" or "Confirm") to close message box.'''      # get handles of all top windows      h_windows = []      win32gui.EnumWindows(lambda hWnd, param: param.append(hWnd), h_windows)       # check each window          for h_window in h_windows:                   # get child button with text OK, Yes or Confirm of given window          h_btn = win32gui.FindWindowEx(h_window, None,'Button', None)          if not h_btn: continue          # check button text          text = win32gui.GetWindowText(h_btn)          if not text.lower() in ('ok', 'yes', 'confirm'): continue          # click button          win32gui.PostMessage(h_btn, win32con.WM_LBUTTONDOWN, None, None)          time.sleep(0.2)          win32gui.PostMessage(h_btn, win32con.WM_LBUTTONUP, None, None)          time.sleep(0.2)

最后,实例演示结束全文,以后再也不用担心意外弹窗了。

[^1]: Handling VBA popup message boxes in Microsoft Excel

[^2]: Trying to catch MsgBox text and press button in xlwings

[^3]: What is pywinauto

[^4]: Remote Execution Guide

上述内容就是如何使用Python子进程关闭Excel自动化中的弹窗,你们学到知识或技能了吗?如果还想学到更多技能或者丰富自己的知识储备,欢迎关注行业资讯频道。

自动化 线程 代码 问题 方式 方案 方法 标题 知识 函数 文件 服务 监听 进程 两个 主程序 内容 参数 同时 技能 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 诛仙服务器合并 商丘网络安全系统厂商 密云erp软件开发企业 服务器在手机上能安装吗 软件开发有哪些小组 派出所网络安全培训方案 云收单软件开发需要多长时间 网络安全短视频乱扫码危害大 糖尿病数据库 网络安全依赖的基本技术 数据库与数据挖掘区别 小程序云存储文件服务器 海尔软件开发岗位 数据库表单删除 网络安全技术设计方法 禾连科技网络技术有限公司 云服务器怎么改背景图 360服务器安全防护开启 渝中区电话网络技术服务活动方案 数据库编号能不能修改 杭州前端软件开发大概要多少钱 曹妃甸区电子网络技术诚信合作 软件开发与创新5000字论文 网络安全依赖的基本技术 web服务器安全检测 线上教学与网络安全心得体会博客 崇义软件开发文档在线咨询 数据库固定格式数据编码 小学网络技术 试卷及答案 国家积极开展网络安全
0