利用Python子进程关闭Excel自动化过程出现的弹窗
利用Python进行Excel自动化操作的过程中,尤其是涉及VBA时,可能遇到消息框/弹窗(MsgBox)。此时需要人为响应,否则代码卡死直至超时 1 2。根本的解决方法是VBA代码中不要出现类似弹窗,但有时我们无权修改被操作的Excel文件,例如这是我们进行自动化测试的对象。所以本文记录从代码角度解决此类问题的方法。
假想场景
使用xlwings
(或者其他自动化库)打开Excel文件test.xlsm
,读取Sheet1!A1
单元格内容。很简单的一个操作:
import xlwings as xwwb = 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代码相应卡死在第一行。
基本思路
主程序中不可能直接处理或者绕过此类问题,也不能奢望有人随时蹲守解决此类问题——那就开启一个子线程来坚守吧。因此,解决方案是利用子线程监听并随时关闭弹窗,直到主程序圆满结束。
Excel中MsgBox
弹窗的默认标题是Microsoft Excel
,接下来以此为例捕捉窗口,并通过点击按钮关闭它。
pywinauto方案
pywinauto
顾名思义是Windows界面自动化库,模拟鼠标和键盘操作窗体和控件 3。不同于先获取句柄再获取属性的传统方式,pywinauto
的API更加友好和pythonic。例如,两行代码就可以实现窗口捕捉和点击:
win = Application(backend="win32").connect(title='Microsoft Excel')
win.Dialog.Button.click()
有关Python多线程的知识不在此展开,本文采用自定义线程类的方式,启动线程后自动执行run()
函数。具体代码如下,构造函数中的两个参数:
title
需要捕捉的弹窗的标题,例如Excel弹窗默认为Microsoft Excel
interval
监听的频率,即每隔多少秒就检查一次
# listener_pywinauto.py
import time
from threading import Thread, Event
from pywinauto.application import Applicationclass 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()@propertydef 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', 1)t.start()time.sleep(10)t.stop()
于是,整个过程分为三步:
- 启动子线程监听弹窗
- 主线程中打开Excel开始自动化操作
- 关闭子线程
import xlwings as xw
from listener_pywinauto 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
(pywin32
库的一部分),所幸解决了上述问题。
# pip install pywin32
import win32gui
import win32con
以下仅列出MsgBoxListener
类中关闭弹窗的步骤,其余代码完全一致:
def _close_msgbox(self):# find the top window by titlehwnd = win32gui.FindWindow(None, self._title)if not hwnd: return# find child buttonh_btn = win32gui.FindWindowEx(hwnd, None,'Button', None)if not h_btn: return# show texttext = 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
)来关闭窗口。
def _close_msgbox(self):'''Click button to close message box if has text "OK", "Yes" or "Confirm".'''# Get handles of all top wondowsh_windows = []win32gui.EnumWindows(lambda hWnd, param: param.append(hWnd), h_windows) 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 texttext = win32gui.GetWindowText(h_btn)if not text.lower() in ('ok', 'yes', 'confirm'): continue# click buttonwin32gui.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)
全文结束,以后再也不怕意外弹窗了。
Handling VBA popup message boxes in Microsoft Excel ↩︎
Trying to catch MsgBox text and press button in xlwings ↩︎
What is pywinauto ↩︎
Remote Execution Guide ↩︎
利用Python子进程关闭Excel自动化过程出现的弹窗相关推荐
- python对数据进行合并的函数_利用Python pandas对Excel进行合并的方法示例
前言 在网上找了很多Python处理Excel的方法和代码,都不是很尽人意,所以自己综合网上各位大佬的方法,自己进行了优化,具体的代码如下. 博主也是新手一枚,代码肯定有很多需要优化的地方,欢迎各位大 ...
- python自动汇总excel_RPA手把手:Python轻松实现EXCEL自动化
原标题:RPA手把手:Python轻松实现EXCEL自动化 了解RPA请访问: www.i-search.com.cn 艺赛旗-RPA机器人免费下载: www.i-search.com.cn/inde ...
- python利用pandas合并excel表格代码_利用Python pandas对Excel进行合并的方法示例
前言 在网上找了很多Python处理Excel的方法和代码,都不是很尽人意,所以自己综合网上各位大佬的方法,自己进行了优化,具体的代码如下. 博主也是新手一枚,代码肯定有很多需要优化的地方,欢迎各位大 ...
- python pandas合并单元格_利用Python pandas对Excel进行合并的方法示例
前言 在网上找了很多Python处理Excel的方法和代码,都不是很尽人意,所以自己综合网上各位大佬的方法,自己进行了优化,具体的代码如下. 博主也是新手一枚,代码肯定有很多需要优化的地方,欢迎各位大 ...
- 2020互联网数据分析师教程视频 统计学分析与数据实战 r语言数据分析实战 python数据分析实战 excel自动化报表分析实战 excel数据分析处理实战
2020互联网数据分析师教程视频 统计学分析与数据实战 r语言数据分析实战 python数据分析实战 excel自动化报表分析实战 excel数据分析处理实战
- python自动化测试脚本可以测php吗_利用Python语言实现实验室自动化
作为一名系统和应用工程师,得益于自动化仪器和软件,我已经节省了不计其数的日日夜夜;例如LabVIEW,这是一款系统设计平台和开发环境,支持可视化编程语言.LabVIEW支持用户利用友好的图形用户界面( ...
- 怎么用python编写个apk_【android】如何利用python做Android项目自动化构建,并一键实现构建结果发送到钉钉通知以及通过二维码下载apk或者其他处理等功能...
今天我们来谈一谈用python做Android项目自动化构建的过程.我们知道在常规的Android开发过程中,开发人员打包的时候需要在Android Studio当中进行,或者通过gradle命令,但 ...
- 利用python实现百度竞价自动化效果监控
百度竞价效果监控 很多客户朋友做了百度推广,全国或者多地区推广,很多时候监控不到本地以外城市的推广情况,不方便推广的调整. 问题 百度推广可以选择不同地区不同出价策略和不同的创意等,但是监控不到数据的 ...
- 【利用python+pandas 拆分excel表格】
利用python拆分excel表格 我们常常会遇到一个表格中包含各种类型的数据,想要把表格按照不同类型拆分到多个工作簿,使用python几行代码就可以轻松搞定 首先是安装需要的包 先cmd命令行安装下 ...
最新文章
- 我用YOLOX露了一手,记录一下模型部署、优化及训练的实现全过程
- MySQL索引管理及执行计划
- python多进程共享内存
- Android进阶知识:绘制流程(上)
- shell命令tree
- 开源分布式中间件 DBLE 快速入门指南
- C++ 有参构造 无参构造 拷贝构造 以及参数化列表 成员对象之间的执行关系
- oracle database 11g plsql 程序设计,oracle-database-11g-plsql-编程实战笔记
- socket接收时信号量阻塞了会丢数据吗_浅谈Java网络编程——非阻塞I/O
- PDFsam Basic for mac(合并拆分PDF文档)支持m1
- USACO Section 1.2 Name That Number
- C语言猜数字小游戏---详解+源码
- 高等数学(第七版)同济大学 习题2-2 个人解答(前7题)
- 芝诺数解|「十一」千里姻缘一“线”牵—重庆网络婚恋分析报告
- 快手申请快手联盟商选商标,商标注册的申请程序有哪些?
- 打开浏览器默认打开hao123网站的主页怎么取消设置?
- ElementUI table 单元格编辑合并
- 李佳琦以特殊人才落户上海,“带货一哥”即将成为“新上海人”
- HDFS RPC 调度策略 DecayRpcScheduler 与 BackOff
- Studio5000和SE中如何使用替换功能
热门文章
- 【饮食的迷思--人类必看的真正的饮食长寿指南--来自英国国王学院顶级遗传性流行病教授】---智人必须会的生活技能 by Tim Spector--饮食的迷思
- Anaconda => PyCharm => CUDA => cudnn => PyTorch 环境配置
- mac下编译安卓源码
- 【JavaScript】案例1:使用JS完成注册页面校验
- 神州优车粗暴裁员:人与人之间最起码的尊重呢?
- 客户体验决胜2022,低代码是快速取胜之道
- css实现带边框,半透明气泡定位浮层效果
- 安卓搭建文件共享服务器,安卓文件共享云服务器
- Unity Sunny Land开发流程(二)
- 第二章:Java面向对象:抽象(abstract)类、模板方法设计模式、接口(interface)、关键字-implements(实现)、代理模式