:同花順客戶端自動化與驗證碼彈窗處理詳解)
做桌面端自動化的朋友應該都有同感Windows 原生應用的自動化跟網(wǎng)頁自動化完全不是一回事。我最早接觸 pywinauto 這個庫是因為想把同花順客戶端里每天重復的幾組固定操作串起來跑。原本以為無非就是“定位控件、發(fā)送點擊、輸入文本”結(jié)果真正上手才發(fā)現(xiàn)驗證碼識別和界面彈窗這兩關(guān)就夠喝一壺。前前后后折騰了將近三周踩了無數(shù)坑最終才把一個穩(wěn)定的自動化流程跑起來。這篇文章就把我在同花順場景下使用 pywinauto 的完整實戰(zhàn)過程寫出來重點拆解驗證碼識別和彈窗處理這兩塊最容易翻車的地方同時也給準備入坑的朋友一個真實的技術(shù)路線參考。如果你正打算做類似的 Windows 原生客戶端自動化這文應該能幫你少走很多彎路。1. 項目整體設(shè)計與技術(shù)選型1.1 需求拆解自動化任務到底要經(jīng)過哪些鏈路先把目標拆清楚。以同花順 PC 客戶端為對象一個完整的自動化操作鏈路通常包含這七步啟動客戶進程、連接并識別主窗體、輸入賬戶密碼、識別并填寫驗證碼、處理登錄后的各類彈窗、進入指定業(yè)務模塊執(zhí)行具體操作、最后處理業(yè)務過程中的確認提示。每一步之間都有依賴關(guān)系任何一步卡住后面的流程就全廢了。我一開始犯的錯就是想把整個流程一口氣寫成線性代碼結(jié)果驗證碼識別失敗一次后面的腳本就全部崩掉。真正穩(wěn)定的做法是把整個自動化流程抽象成一個狀態(tài)機。每一步都定義明確的輸入輸出執(zhí)行完成后校驗結(jié)果只有校驗通過才進入下一步。比如登錄階段先輸入賬號密碼再等待驗證碼圖片更新完成后才填驗證碼驗證碼填完后點擊登錄按鈕之后必須等待主窗體出現(xiàn)關(guān)鍵控件而不是簡單睡幾秒鐘。這個習慣可以說救了我很多次因為同花順的網(wǎng)絡延遲、驗證碼刷新時間、彈窗出現(xiàn)時機全都不是固定的只有狀態(tài)校驗才能應付這種不確定。1.2 為什么最終選 pywinauto而不是 UIAutomation 或按鍵精靈市面上能做桌面自動化的方案不少我實際對比過三類。第一類是按鍵精靈這類錄制回放工具優(yōu)點是沒有門檻但靈活性很差界面一改腳本就得重新錄制而且它對接 Python 生態(tài)也比較吃力要做圖像處理和 OCR 得額外想辦法。第二類是 UIAutomation 庫它是另一種封裝 UI Automation 的 Python 庫底層能力并不比 pywinauto 弱但社區(qū)活躍度和文檔完善程度都不如 pywinauto對自繪控件的處理也沒有 pywinauto 那么成熟。第三類就是 pywinauto 本身它同時支持 win32 和 uia 兩種后端既能處理標準 Win32 控件也能用 UI Automation 去碰那些自繪控件和現(xiàn)代控件搭配 Python 做圖像處理和 OCR 非常順。我的最終選型是 pywinauto 加 OpenCV 加 OCR 庫的組合。pywinauto 負責所有界面操作OpenCV 負責把驗證碼圖片處理成適合識別的狀態(tài)OCR 負責把圖片內(nèi)容轉(zhuǎn)成文本。這個組合的好處是每一層都能獨立替換比如 OCR 引擎今天用 ddddocr明天想換成 PaddleOCR只需要改接口實現(xiàn)不影響整體流程。對于同花順這種以自繪控件為主的客戶端pywinauto 的 uia 后端在控件識別方面表現(xiàn)還算可以配合坐標兜底基本能覆蓋絕大多數(shù)場景。1.3 同花順客戶端的特殊性分析同花順客戶端跟普通的 Windows 應用比起來有幾個非常突出的特殊性。第一個是控件大量自繪很多按鈕、輸入框、列表都不是標準控件你在 pywinauto 的控件樹里根本找不到對應的 class_name 和 control_type這種情況下只能靠坐標點擊或者圖像匹配來兜底。第二個是進程和窗體不唯一它可能同時存在主窗口、彈出窗口、資訊窗口等多個頂層窗口用 connect 連接的時候如果只按標題匹配很容易抓到錯誤的窗口。第三個是驗證碼的更新機制有點奇怪驗證碼圖片并不是每次刷新都會生成新圖偶爾會出現(xiàn)“同一張圖重復展示”的情況這給 OCR 緩存帶來了麻煩——如果你做過結(jié)果緩存可能會把上一次的識別結(jié)果直接提交結(jié)果服務端返回驗證碼錯誤。第四個是彈窗種類特別多從版本更新提示、風險揭示書、公告到下單確認、撤單確認、價格偏離風險提示甚至還有行情推送的氣泡窗口。如果不做專門的彈窗處理模塊任何一個未預期的彈窗都可能打斷主流程導致腳本卡死在等待某個控件出現(xiàn)的狀態(tài)。后面我會專門把彈窗這塊單獨拿出來講。2. 環(huán)境準備與核心原理2.1 Python 環(huán)境與依賴安裝這個項目我用的是 Python 3.10理論上 3.8 以上都能跑。依賴庫有以下這些pywinauto 用于界面自動化Pillow 用于圖像截圖和處理opencv-python 用于驗證碼圖像的灰度化、二值化、去噪等預處理pytesseract 和 ddddocr 作為 OCR 引擎numpy 作為圖像處理的底層依賴。安裝命令非常簡單一行 pip 就能搞定大部分pip install pywinauto pillow opencv-python numpy pytesseract ddddocr需要注意pytesseract 是一個 Python 封裝它本身依賴 Tesseract OCR 引擎。Windows 下你需要單獨下載安裝 tesseract 程序并把它的安裝路徑加入系統(tǒng)環(huán)境變量否則調(diào)用 image_to_string 時會報“tesseract is not installed”之類的問題。ddddocr 不需要額外安裝引擎但它在某些 Windows 環(huán)境下會依賴特定版本的 numpy如果安裝后導入報錯可以試試把 numpy 降級到 1.24 左右。我本地測試環(huán)境是 Windows 10 專業(yè)版1920x1080 分辨率系統(tǒng)縮放設(shè)置為 125%。這里提醒一句系統(tǒng)縮放比例對 pywinauto 的坐標計算有影響如果你的腳本里混用了控件識別和坐標點擊一定要把縮放因素考慮進去最好在腳本啟動時讀取系統(tǒng) DPI 設(shè)置再做坐標換算。2.2 pywinauto 核心概念速覽backend、Application 與 Desktoppywinauto 最核心的概念就是 backend。它有兩個后端win32 和 uia。win32 后端走的是傳統(tǒng)的 Win32 API速度更快適合處理標準控件uia 后端走的是 UI Automation 框架能識別更多現(xiàn)代控件和部分自繪控件的語義比如按鈕即使沒有標準窗口句柄也能通過 control_type 暴露出來但速度相對慢一些。我的經(jīng)驗是同花順場景優(yōu)先用 uia遇到識別不到的情況再用 win32 做對比測試。Application 類是用來連接或啟動目標應用的入口。連接已運行的同花順通常這樣寫from pywinauto import Application app Application(backenduia).connect(title_re同花順) win app.window(title_re同花順) print(win.print_control_identifiers())print_control_identifiers 是最重要的調(diào)試工具它能把當前窗口的整個控件樹打印出來包括每個控件的 class_name、control_type、title、auto_id 等屬性。我強烈建議拿到一個不熟悉的窗口時第一件事就是先打印控件樹看看結(jié)構(gòu)再決定用哪種方式定位目標控件。Desktop 類則是一個虛擬的“根窗口”可以用來遍歷當前桌面上所有的頂層窗口。這個在彈窗監(jiān)控中特別有用因為你不知道彈窗什么時候出現(xiàn)需要在后臺實時巡檢所有窗口。2.3 連接同花順主窗體的兩種方式與踩坑連接同花順主窗體我實驗下來有兩種靠譜方式。第一種是直接按進程名連接適合同花順只開了一個進程的情況import psutil from pywinauto import Application for proc in psutil.process_iter([pid, name]): if hexin in proc.info[name].lower() or 同花順 in proc.info[name]: app Application(backenduia).connect(pidproc.info[pid]) break第二種是按標題正則連接。同花順主窗口的標題通常會包含“同花順”三個字直接connect(title_re.*同花順.*)就行但問題是有時候會同時匹配到多個窗口這時候需要進一步判斷哪個是主窗口哪個是資訊彈窗或置頂小窗。我的處理方式是先連接再遍歷該連接下的所有頂層窗口挑選出包含核心業(yè)務控件比如搜索框、自選股列表的那個窗口作為主窗口。這里有個很大的坑同花順啟動后可能有多個進程而且主進程不一定叫“同花順.exe”它有可能是 hexin.exe、hexsrv.exe 之類。直接用窗口標題連接可以繞過這個麻煩但要注意標題里的“同花順”字樣在版本更新后可能變化所以更保險的做法是先用Desktop(backenduia).windows()打印出所有頂層窗口的標題、類名、進程ID再寫正則規(guī)則來匹配。我第一次做的時候沒打印窗口列表直接用猜的標題去連接結(jié)果連接到的只是一個包含“同花順”字樣的行情推送彈窗白白浪費了一個晚上排查。3. 驗證碼識別實戰(zhàn)從截圖到輸出文本3.1 同花順驗證碼的常見形態(tài)與識別難度評估同花順客戶端登錄時會出現(xiàn)一個四到五位字符的驗證碼通常由數(shù)字和字母混合組成。從我的觀察來看這個驗證碼并不算特別復雜干擾線不多背景有輕微噪點字符有一定程度扭曲但沒有粘連到無法辨識的程度。相比那些帶復雜扭曲、旋轉(zhuǎn)、背景紋理的極驗證碼同花順的算是中等偏下難度這給 OCR 識別提供了基礎(chǔ)條件。不過它有一個比較麻煩的地方驗證碼的字體風格偶爾會變。同一臺機器、同一個賬號今天可能是方正的宋體樣式過幾天可能變成帶尖角的藝術(shù)體樣式。字體變化會讓訓練好的 OCR 模型準確率明顯下降這也是我后來選擇走“通用 OCR 加后處理”路線而不是“專用分類模型”的原因之一。如果你打算訓練一個 CNN 分類器來識別要注意持續(xù)收集新樣本不然模型會隨著字體變化慢慢失效。3.2 截圖定位如何準確獲取驗證碼圖片區(qū)域要讓 OCR 有好的輸入第一步是把驗證碼圖片準確截下來。如果驗證碼是標準控件可以直接通過 pywinauto 獲取控件的 bounding rectangle然后截圖。但同花順里的驗證碼往往是自繪的控件樹里沒有獨立節(jié)點這時候需要用圖像匹配兜底。我用的方案是先利用窗口內(nèi)一個固定參照物計算縮放比例再根據(jù)人工測量得出的相對位置去截取驗證碼區(qū)域。比如主窗體的大小不一定固定但驗證碼圖片相對于某個已知控件的位置比例是穩(wěn)定的。代碼大致是這樣import ctypes from PIL import ImageGrab user32 ctypes.windll.user32 user32.SetProcessDPIAware() rect win.rectangle() left, top rect.left, rect.top width rect.right - rect.left height rect.bottom - rect.top # 根據(jù)經(jīng)驗比例計算驗證碼區(qū)域 captcha_left int(left width * 0.55) captcha_top int(top height * 0.42) captcha_right int(left width * 0.72) captcha_bottom int(top height * 0.48) captcha_img ImageGrab.grab(bbox(captcha_left, captcha_top, captcha_right, captcha_bottom)) captcha_img.save(captcha.png)SetProcessDPIAware 這行非常關(guān)鍵。如果你的系統(tǒng)開啟了縮放Python 默認拿到的窗口坐標和圖像實際坐標可能不一致導致截圖偏移。做過桌面圖像處理的應該都明白截圖區(qū)域稍微歪一點后續(xù)識別率就會直線下降。3.3 圖像預處理流程灰度化、去噪、二值化與形態(tài)學截圖拿到之后不能直接扔給 OCR。原始驗證碼圖片通常帶背景色和噪點直接識別的效果很差。我的預處理流程如下先灰度化再高斯模糊去噪然后二值化最后做一次形態(tài)學閉運算?;叶然前巡蕡D轉(zhuǎn)成單通道減少顏色干擾高斯模糊可以去掉細小噪點但卷積核不能太大否則字符也會被抹掉二值化是把像素分成黑白兩類讓背景和字符完全分離閉運算的作用是把字符中斷開的筆畫連接起來因為二值化之后字符筆畫經(jīng)常出現(xiàn)斷裂。import cv2 import numpy as np img cv2.imread(captcha.png, cv2.IMREAD_GRAYSCALE) _, binary cv2.threshold(img, 0, 255, cv2.THRESH_BINARY cv2.THRESH_OTSU) kernel cv2.getStructuringElement(cv2.MORPH_RECT, (2, 2)) closed cv2.morphologyEx(binary, cv2.MORPH_CLOSE, kernel) cv2.imwrite(captcha_processed.png, closed)閾值選擇我用的是大津法OTSU不用手動指定閾值它能根據(jù)圖像灰度分布自動計算最佳分割點。實測下來同花順驗證碼在 OTSU 下效果不錯字跡清晰。形態(tài)學閉運算的卷積核大小需要根據(jù)字符尺寸調(diào)整我這邊 2x2 尺寸剛好再大一點會把相鄰字符連在一起反而影響識別。3.4 OCR 識別與后處理ddddocr 與 pytesseract 雙引擎預處理完成后進入 OCR 環(huán)節(jié)。我同時準備了兩個引擎一個是 ddddocr另一個是 pytesseract。ddddocr 是專門為驗證碼場景訓練的模型對數(shù)字字母混合驗證碼識別率很高調(diào)用非常簡單import ddddocr ocr ddddocr.DdddOcr(show_adFalse) with open(captcha_processed.png, rb) as f: image f.read() result ocr.classification(image) print(識別結(jié)果:, result)ddddocr 的缺點是模型是固定的遇到字體風格變化時準確率會波動。pytesseract 則更通用可以配置識別模式和白名單適合處理清晰但風格多變的字符import pytesseract from PIL import Image text pytesseract.image_to_string( Image.open(captcha_processed.png), config--psm 7 -c tessedit_char_whitelistABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789 )psm 7 表示將圖片視為一行文本特別適合驗證碼這種單行字符。白名單限制了只識別字母和數(shù)字能排除各種標點符號干擾。兩個引擎我會同時跑如果結(jié)果一致就直接采用如果不一致再用字符長度過濾和常見混淆規(guī)則比如 0 和 O、1 和 l、2 和 Z來做最后決斷。后處理這塊容易被忽視但它很關(guān)鍵。OCR 識別出的文本可能帶空格、帶換行、帶多余字符一定要做清洗。同花順驗證碼通常是四到五個字符所以清洗后如果長度不符合基本可以判定識別失敗直接重新刷新驗證碼再試。3.5 提高識別率的三個細節(jié)經(jīng)驗第一個經(jīng)驗是不要盲目追求單次識別率要把“識別失敗后重新刷新”納入整體流程。同花順驗證碼可以通過點擊驗證碼圖片刷新也可以點擊旁邊的刷新按鈕。我實測下來每次重新截圖的識別成功率在 75% 左右但加上了失敗后自動刷新重試三次以內(nèi)成功的概率能到 95% 以上。所以流程設(shè)計上驗證碼識別環(huán)節(jié)一定要有次數(shù)限制和超時退出不能無限重試。第二個經(jīng)驗是保存識別日志。把每次的驗證碼圖片、預處理結(jié)果、兩個引擎的識別結(jié)果、最終采用值全部記錄下來。這樣做的好處是一旦某個時段識別率下降你可以復盤到底是因為圖片質(zhì)量差、字體變化還是預處理參數(shù)失效。我通過日志發(fā)現(xiàn)過一次規(guī)律下午時段驗證碼背景噪點明顯增多后來調(diào)整了高斯模糊的參數(shù)才穩(wěn)住。第三個經(jīng)驗是驗證碼出現(xiàn)后延遲一小會兒再截圖。剛刷新出來的驗證碼圖片如果立刻截圖偶爾能截到半渲染狀態(tài)圖片內(nèi)容不完整。我實測加了個 0.3 到 0.5 秒的等待識別率有明顯提升。這種細節(jié)不跑上幾十次很難發(fā)現(xiàn)屬于典型的頁面渲染時序問題。4. 界面彈窗處理的完整方案4.1 同花順彈窗類型盤點識別特征與響應策略同花順客戶端的彈窗多到令人發(fā)指。我粗略統(tǒng)計了一下整個流程中可能遇到的彈窗種類有十幾類登錄階段的風險揭示書、用戶協(xié)議更新登錄后的“推薦股票”營銷彈窗、“版本升級提示”、公告通知操作階段的下單確認、撤單確認、價格偏離風險提示、無持倉確認還有不定時出現(xiàn)的行情推送氣泡、系統(tǒng)維護提醒。每種彈窗的標題和按鈕文本都不一樣有的需要點確定有的需要選是有的需要點關(guān)閉。要穩(wěn)定處理這么多彈窗第一步是建立一張彈窗特征表。每條記錄包含彈窗標題正則、按鈕文本、處理動作、是否阻塞主流程等字段。比如“風險揭示”這個彈窗標題匹配到之后主流程必須等它消失才能繼續(xù)處理動作是點擊“我已閱讀并同意”“推薦股票”彈窗是非阻塞的處理動作是直接關(guān)閉?!鞍姹旧墶睆棿耙貏e小心如果點了確定它可能開始下載升級包反而更糟所以動作是點“取消”或“以后再說”。這里容易踩坑的地方在于有些彈窗的標題和按鈕文本會隨版本更新改變。寫死字符串的腳本一旦遇到版本升級彈窗處理模塊就失效了。我的做法是把彈窗規(guī)則放在一個 JSON 配置文件里文本變更時只改配置不碰代碼。這個設(shè)計讓我在后續(xù)同花順自動更新之后省了很多事。4.2 彈窗監(jiān)控與自動響應的兩種實現(xiàn)方式處理彈窗有兩種思路一種是主流程“主動查詢”另一種是后臺“被動監(jiān)控”。我一開始用的是主動查詢也就是在每個關(guān)鍵操作之后遍歷一遍所有頂層窗口看看有沒有需要處理的彈窗。這種方式的缺點是邏輯耦合嚴重主流程里塞滿了彈窗判斷代碼代碼可讀性很差。后來我改成被動監(jiān)控專門開一個后臺線程每隔 0.3 秒遍歷一次桌面所有頂層窗口找到匹配彈窗特征表的窗口就自動執(zhí)行對應動作。主流程只需要關(guān)心自己本來要做的事情彈窗處理完全解耦。這個設(shè)計是我整個項目里最值得分享的一個點。代碼骨架大致這樣import threading import time from pywinauto import Desktop def monitor_popups(stop_event): desktop Desktop(backenduia) rules load_popup_rules(popup_rules.json) processed set() while not stop_event.is_set(): try: windows desktop.windows() for w in windows: title w.window_text() handle w.handle if handle in processed: continue for rule in rules: if rule[title_re] in title or title in rule[title_re]: handle_popup(w, rule) processed.add(handle) break except Exception: pass time.sleep(0.3)processed 集合用來記錄已經(jīng)處理過的窗口句柄防止同一個彈窗被重復處理。這個很關(guān)鍵比如一個彈窗關(guān)閉后還沒完全消失下一輪巡檢又匹配到它就會再次點擊導致不必要的誤操作。被動監(jiān)控有個好處它不僅能處理預期內(nèi)的彈窗還能兜底處理那些意外出現(xiàn)的彈窗。比如有一次同花順突然彈了一個“連接超時重試”的提示框如果不處理主流程會一直等一個永遠不會出現(xiàn)的控件。有了監(jiān)控線程這種彈窗也能被及時關(guān)掉。4.3 彈窗處理中的競態(tài)問題與重試機制彈窗處理最常見的坑就是競態(tài)條件。彈窗剛出現(xiàn)時控件可能還沒有完全創(chuàng)建好后臺線程立刻去查找按鈕就會拋 ElementNotFoundError。這個問題的標準解法是用 pywinauto 的 wait 方法在點擊按鈕之前先等待按鈕 exists 或 visible。同時要包一層 try-except捕獲超時異常后繼續(xù)重試。另一個競態(tài)是彈窗還沒完全消失主流程就已經(jīng)繼續(xù)往下走結(jié)果后續(xù)操作因為窗口遮擋而失敗。比如下單確認彈窗點完確定后如果立刻去查持倉列表可能因為倉位刷新延遲或彈窗殘留導致數(shù)據(jù)不準確。我的處理方式是在每次關(guān)鍵操作后等待一個確定性條件比如某個狀態(tài)控件的文本變化、某個按鈕可用而不是單純等待幾秒鐘。最后說下重試機制。任何一次彈窗點擊都不能只試一次我封裝了一個帶重試的 click 函數(shù)最多重試三次每次間隔 0.5 秒。如果三次都失敗就記錄日志并切換策略比如改用坐標點擊。這套重試機制在彈窗處理上看似大材小用實際跑起來卻能顯著提高整體成功率因為同花順的彈窗動畫和渲染速度在不同機器上差異很大。5. 常見問題與排查技巧實錄5.1 控件定位失敗print_control_identifiers 的正確用法控件定位失敗是我遇到最多的問題基本集中在兩類場景。第一類是控件屬性為空class_name、title、control_type 全都拿不到第二類是錯誤地匹配到了同名的隱藏控件。遇到這種情況第一反應用win.print_control_identifiers(depth2)打印控件樹看清整個窗口的結(jié)構(gòu)而不是盲目地換一個屬性繼續(xù)猜。打印出來的控件樹里你要重點關(guān)注 auto_id、control_type、title 這幾個字段的組合。同花順有些按鈕 title 是空的但 control_type 是 Buttonauto_id 是唯一標識。有些輸入框無法通過標準屬性定位但在控件樹里能看到它的 class_name 是某個特定值可以拿來做篩選。如果控件樹里完全沒有目標控件說明它是純自繪控件這時候只能靠坐標或者圖像識別兜底。我還發(fā)現(xiàn)一個技巧用child_window()的時候可以同時傳多個條件比如 title 和 control_type 一起匹配能大幅降低誤匹配概率。但要注意多個條件之間是 AND 關(guān)系如果其中一個條件寫錯了結(jié)果就是空集這時候不要懷疑 pywinauto 有問題先逐個條件驗證一下。5.2 自繪控件無法識別時的坐標兜底方案同花順的某些功能按鈕比如“買入”“賣出”“撤單”在控件樹里完全不存在。我用 uia 后端查看連整個窗口都只有寥寥幾個節(jié)點這時候只能退回到坐標點擊。坐標點擊的原理很簡單通過窗口矩形和已知參照物的相對比例計算點擊位置然后調(diào)用win.click(coords(x, y))。這里有個非常重要的細節(jié)pywinauto 的 click 坐標是相對于窗口客戶區(qū)的不是屏幕坐標。而 ImageGrab 截圖用的是屏幕坐標所以兩套坐標體系需要明確換算。窗口客戶區(qū)左頂點可以通過win.client_rect()獲取再加上相對偏移才是目標控件的位置。我因為坐標算錯空跑了一整夜才發(fā)現(xiàn)點的地方根本不是目標按鈕。坐標兜底雖然能用但它脆弱窗口大小變化、界面布局微調(diào)都會讓坐標失效。所以我的建議是優(yōu)先控件定位、其次坐標兜底并且盡量把主窗口最大化固定減少布局變動。如果你愿意再上一層可以用模板匹配的方式找到目標按鈕的圖像位置然后換算成坐標這樣對布局變化的容忍度會高很多。5.3 權(quán)限、安全機制與運行穩(wěn)定性提升同花順客戶端有一定程度的自我保護機制這在桌面自動化中很常見。有幾點經(jīng)驗值得分享。第一Python 環(huán)境盡量以管理員權(quán)限運行否則某些窗口消息會被 UAC 攔截導致 click 操作無效。第二不要高頻操作同花順對異常高頻的登錄、下單請求有風控策略太激進的話容易觸發(fā)臨時限制。我的做法是在每次操作之間加一個隨機延遲比如 0.5 到 1.5 秒之間隨機取既保證效率又讓行為更接近真人。第三腳本要加完整的日志系統(tǒng)。我用的方案是 Python logging 輸出到控制臺和文件同時記錄每次操作的耗時、控件截圖、異常堆棧。排查問題的時候日志和截圖能節(jié)省大量時間。第四腳本要設(shè)計成可中斷、可恢復的。自動化跑著跑著可能崩潰如果不能恢復就得從頭再來。我的做法是記錄狀態(tài)文件每次關(guān)鍵步驟完成后寫入當前狀態(tài)重啟后從狀態(tài)文件恢復。第五也是最重要的一點任何自動化操作之前務必閱讀同花順的用戶協(xié)議和相關(guān)法律法規(guī)。自動化操作證券客戶端在特定場景下可能違反軟件使用條款甚至觸發(fā)合規(guī)風險。本文所有技術(shù)內(nèi)容僅用于學習和軟件測試目的請務必在你合法擁有的測試環(huán)境或模擬環(huán)境中驗證實際作用于真實業(yè)務前請咨詢專業(yè)人士。5.4 常見異常速查表為了方便排查我把實際遇到的高頻異常整理成一張速查表遇到問題直接對著查。異?,F(xiàn)象可能原因排查與解決方法connect 連接不上同花順進程名或標題不匹配先打印所有頂層窗口確認實際標題、類名和進程ID控件樹為空選錯了 backend 或窗口句柄換成 uia 后端或者重新確認連接的窗口是主窗口click 點了沒反應窗口最小化/被遮擋/按鈕自定義繪制先 activate 窗口再確認坐標是相對客戶區(qū)必要時截圖確認按鈕位置驗證碼識別率突然下降字體風格變化或圖片噪點增多保存截圖日志調(diào)整預處理參數(shù)或切換 OCR 引擎彈窗處理重復點擊processed 集合未正確記錄用窗口句柄做去重彈窗消失后從集合中刪除該句柄系統(tǒng)縮放導致坐標偏移未設(shè)置 DPI 感知腳本開頭調(diào)用 SetProcessDPIAware或按 DPI 縮放比例換算坐標操作太頻繁被風控請求頻率過高增加隨機延遲降低操作頻率避免短時間內(nèi)大量重復動作這張表不是一次性列出來的而是我跑了兩個多星期、掛了十幾次機之后一點點沉淀下來的。每次掛了機我就看日志定位原因然后往表里加一條。做自動化最忌諱的是盲目重試一定要有記錄、有復盤、有迭代。6. 實戰(zhàn)心得與最終體會整個項目做下來我最深的感觸是桌面自動化真正的難點不在“如何寫到代碼”而在“如何設(shè)計容錯”。驗證碼識別和彈窗處理本質(zhì)上都是容錯設(shè)計的問題。驗證碼識別率不可能到 100%你就必須設(shè)計重試、刷新、多引擎投票機制彈窗類型不可能完全枚舉你就必須設(shè)計監(jiān)控線程、規(guī)則配置、去重機制。把這兩塊做好之后整個流程的穩(wěn)定性自然會上去。技術(shù)選型上pywinauto 作為主框架是沒問題的它雖然有一些歷史包袱接口設(shè)計也不算現(xiàn)代但勝在穩(wěn)定、社區(qū)大、遇到問題搜得到答案。OCR 環(huán)節(jié)我強烈建議保留雙引擎配置ddddocr 和 pytesseract 各有千秋雙引擎投票能覆蓋大部分識別失敗的場景。圖像預處理參數(shù)不要硬編碼在代碼里放到配置文件里方便隨時調(diào)整。同花順自動化的實戰(zhàn)給了我一個非常重要的啟發(fā)你永遠無法預料一個桌面應用在真實運行環(huán)境中會有什么行為。網(wǎng)絡延遲、系統(tǒng)彈窗、字體渲染、分辨率變化每一個因素都可能導致自動化流程失敗。這不是代碼能力的問題而是工程化思維的問題。如果你想做類似的項目我的建議是先跑通最小閉環(huán)再做日志再做容錯再做異常處理。不要一開始就想著把所有功能都實現(xiàn)那樣只會讓自己陷入無盡的調(diào)試泥潭。最后提醒一句自動化你的軟件操作之前一定要先了解并遵守軟件的用戶協(xié)議和你所在地的法律法規(guī)本文所有內(nèi)容僅限學習 GUI 自動化技術(shù)和軟件測試場景使用不構(gòu)成任何操作指引。工具本身沒有對錯關(guān)鍵在于使用工具的人把它用在哪里。