用 Python 子进程关闭 Excel 自动化中的弹窗
Python中文社区
共 7594字,需浏览 16分钟
· 2021-05-07
假想场景
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()
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
更多阅读
特别推荐
点击下方阅读原文加入社区会员
评论
真高!比亚迪员工爆料比亚迪在越南的薪资水平:基本工资480万,全勤奖35万,交通补助20万,餐补110万,每周6天,每天10小时
上一篇:某大公司为逼迫员工离职,竟然把他的工位安排到厕所旁,没想到他直接开始记录领导的如厕时间,还发到公司大群...对此,你怎么看?--完--PS:欢迎在留言区留下你的观点,一起讨论提高。如果今天的文章让你有新的启发,欢迎转发分享给更多人。全文完,感谢你的耐心阅读。如果你还想看到我的文章,请一定给本
开发者全社区
0
太敢穿了!透视纱裙!性感火辣的身材
绝了呀今天的厂花:吴宣仪1995年1月26日,吴宣仪出生于海南省海口市,中国内地流行乐女歌手、影视演员。2016年2月,吴宣仪随宇宙少女发行首张迷你专辑正式出道。2018年4月,她参加《创造101》综艺选秀,获得第二名,成功加入火箭少女101组合。吴宣仪的颜值一直备受称赞,她的五官立体精致,皮肤白皙
逆锋起笔
0
某大公司为逼迫员工离职,竟然把他的工位安排到厕所旁,没想到他直接开始记录领导的如厕时间,还发到公司大群...
上一篇:字节的跳动职级与薪资(2024年)我们与公司间的合作,宛如两艘船只在茫茫大海上相互依靠,共同抵御风浪,携手驶向成功的彼岸。然而,当航向开始产生分歧,或是波涛汹涌的风浪改变了我们的初衷,我们或许应当冷静地选择和平分手,而非在风雨中硬撑。最近,一位网友的遭遇引起了广大职场人的关注和热议。这位网友
开发者全社区
0
金融研究 | 使用Python测量关键审计事项的「信息含量」
Tips: 公众号推送后内容只能更改一次,且只能改20字符。如果内容出问题,或者想更新内容, 只能重复推送。为了更好的阅读体验,建议阅读本文博客版, 链接地址https://textdata.cn/blog/2023-01-13-information-content-of-critical-aud
大邓和他的Python
0
我看阿里的年终奖总算发了!
到4月底了,这两天看朋友圈,发现阿里的年终奖终于发了,问了问老同学,也从网上检索了不少信息,基本搞清楚了阿里今年的年终奖情况。近来来阿里一些集团对绩效等级做了较大的调整,以前的旧绩效系统中,绩效分为3.25、3.5、3.75、4和5五个等级,其中4和5是较高绩效等级,较少见。而且之前3.5绩效内部划
公子龙
0
CVPR 2024|大视觉模型的开山之作!无需任何语言数据即可打造大视觉模型
↑ 点击蓝字 关注极市平台作者丨科技猛兽编辑丨极市平台极市导读 本文提出一种序列建模 (sequential modeling) 的方法,不使用任何语言数据,训练大视觉模型。>>加入极市CV技术交流群,走在计算机视觉的最前沿本文目录1 序列建模打造大视觉模型(来自 U
极市平台
1
金融研究(更新) | 使用Python构建关键审计事项的「信息含量」
Tips: 公众号推送后内容只能更改一次,且只能改20字符。如果内容出问题,或者想更新内容, 只能重复推送。为了更好的阅读体验,建议阅读本文博客版, 链接地址https://textdata.cn/blog/2023-01-13-information-content-of-critical-aud
大邓和他的Python
0
字节的跳动职级与薪资(2024年)
上一篇:阿里公布年终奖,P7, 3.5+,22W年终奖,还有35W长期现金激励,真香字节跳动自2012年3月成立以来,已经迅速成长为一个全球性的科技公司。其产品和服务已经遍布全球150多个国家与地区,并且支持超过75种不同的语言。在字节跳动的官方网站上,列出了一系列引人注目的产品和服务,包括但不限于
开发者全社区
0