av一区二区在线观看_亚洲男人的天堂网站_日韩亚洲视频_在线成人免费_欧美日韩精品免费观看视频_久草视

您的位置:首頁技術(shù)文章
文章詳情頁

如何用 Python 子進(jìn)程關(guān)閉 Excel 自動化中的彈窗

瀏覽:2日期:2022-06-20 13:33:23

利用Python進(jìn)行Excel自動化操作的過程中,尤其是涉及VBA時,可能遇到消息框/彈窗(MsgBox)。此時需要人為響應(yīng),否則代碼卡死直至超時 [^1] [^2]。根本的解決方法是VBA代碼中不要出現(xiàn)類似彈窗,但有時我們無權(quán)修改被操作的Excel文件,例如這是我們進(jìn)行自動化測試的對象。所以本文記錄從代碼角度解決此類問題的方法。

假想場景

使用xlwings(或者其他自動化庫)打開Excel文件test.xlsm,讀取Sheet1!A1單元格內(nèi)容。很簡單的一個操作:

import xlwings as xwwb = xw.Book(’test.xlsm’)msg = wb.sheets(’Sheet1’).range(’A1’).valueprint(msg)wb.close()

然而不幸的是,打開工作簿時進(jìn)行了熱情的歡迎儀式:

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

第一個彈窗Welcome就卡住了Excel,Python代碼相應(yīng)卡死在第一行。

如何用 Python 子進(jìn)程關(guān)閉 Excel 自動化中的彈窗

基本思路

主程序中不可能直接處理或者繞過此類問題,也不能奢望有人隨時蹲守點(diǎn)擊下一步——那就開啟一個子線程來護(hù)航吧。因此,解決方案是利用子線程監(jiān)聽并隨時關(guān)閉彈窗,直到主程序圓滿結(jié)束。解決這個問題,需要以下兩個知識點(diǎn)(基礎(chǔ)知識請課外學(xué)習(xí)):

Python多線程(本文采用threading.Thread) Python界面自動化庫(本文涉及pywinauto和pywin32) pywinauto方案

pywinauto顧名思義是Windows界面自動化庫,模擬鼠標(biāo)和鍵盤操作窗體和控件 [^3]。不同于先獲取句柄再獲取屬性的傳統(tǒng)方式,pywinauto的API更加友好和pythonic。例如,兩行代碼搞定窗口捕捉和點(diǎn)擊:

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

本文采用自定義線程類的方式,啟動線程后自動執(zhí)行run()函數(shù)來完成上述操作。具體代碼如下,注意構(gòu)造函數(shù)中的兩個參數(shù):

title 需要捕捉的彈窗的標(biāo)題,例如Excel默認(rèn)彈窗的標(biāo)題為Microsoft Excel interval 監(jiān)聽的頻率,即每隔多少秒檢查一次

# listener.pyimport timefrom threading import Thread, Eventfrom 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() @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()

于是,整個過程分為三步:

啟動子線程監(jiān)聽彈窗 主線程中打開Excel開始自動化操作 關(guān)閉子線程

import xlwings as xwfrom listener import MsgBoxListener# start listen threadlistener = MsgBoxListener(’Microsoft Excel’, 3)listener.start()# main process as beforewb = xw.Book(’test.xlsm’)msg = wb.sheets(’Sheet1’).range(’A1’).valueprint(msg)wb.close()# stop listener threadlistener.stop()

到此問題基本解決,本地運(yùn)行效果完全達(dá)到預(yù)期。但我的真實(shí)需求是以系統(tǒng)服務(wù)方式在服務(wù)器上進(jìn)行Excel文件自動化測試,后續(xù)發(fā)現(xiàn),當(dāng)以系統(tǒng)服務(wù)方式運(yùn)行時,pywinauto竟然捕捉不到彈窗!這或許是pywinauto一個潛在的問題 [^4]。

win32gui方案

那就只好轉(zhuǎn)向相對底層的win32gui,所幸完美解決了上述問題。win32gui是pywin32庫的一部分,所以實(shí)際安裝命令是:

pip install pywin32

整個方案和前文描述完全一致,只是替換MsgBoxListener類中關(guān)閉彈窗的方法:

import win32gui, win32condef _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)更一般的方案

更一般地,當(dāng)同時存在默認(rèn)標(biāo)題和自定義標(biāo)題的彈窗時,就不便于采用標(biāo)題方式進(jìn)行捕捉了。例如

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'

那就擴(kuò)大搜索范圍,依次點(diǎn)擊所有包含確定性描述的按鈕(例如OK,Yes,Confirm)來關(guān)閉彈窗。同理替換MsgBoxListener類的_close_msgbox()方法(同時構(gòu)造函數(shù)中不再需要title參數(shù)):

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 windowfor h_window in h_windows: # get child button with text OK, Yes or Confirm of given windowh_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)

最后,實(shí)例演示結(jié)束全文,以后再也不用擔(dān)心意外彈窗了。

如何用 Python 子進(jìn)程關(guān)閉 Excel 自動化中的彈窗

以上就是如何用 Python 子進(jìn)程關(guān)閉 Excel 自動化中的彈窗的詳細(xì)內(nèi)容,更多關(guān)于Python 子進(jìn)程關(guān)閉 Excel 彈窗的資料請關(guān)注好吧啦網(wǎng)其它相關(guān)文章!

標(biāo)簽: python
相關(guān)文章:
主站蜘蛛池模板: 欧美日批 | 午夜精品久久久久久久星辰影院 | 日韩一区中文字幕 | 欧美中文字幕一区二区三区亚洲 | 特黄色一级毛片 | 精品91久久| 欧美片网站免费 | 午夜影院操 | 欧美精品一区二区三区在线播放 | 久草热8精品视频在线观看 午夜伦4480yy私人影院 | 色悠悠久 | 欧美午夜精品久久久久免费视 | 户外露出一区二区三区 | 国产美女在线观看 | 亚洲色欲色欲www | 高清人人天天夜夜曰狠狠狠狠 | 97人人澡人人爽91综合色 | 久久国产精品72免费观看 | 性高湖久久久久久久久aaaaa | 亚洲精品观看 | 国产一级黄色网 | 欧美一区免费 | 国产a视频 | 国产精品久久国产精品 | 中文字幕在线看人 | 成人精品一区二区 | 成人欧美一区二区三区1314 | 亚洲欧洲成人av每日更新 | 人人九九 | 欧美一级三级在线观看 | 黄色片免费在线观看 | 成人黄色三级毛片 | 天堂亚洲网 | 亚洲日本免费 | 在线观看黄免费 | 亚洲精品在线看 | 欧美日韩精品亚洲 | 日韩一区二区在线视频 | 中文在线一区二区 | 国产精品美女久久久av超清 | 亚洲欧美日韩系列 |