python辦公自動化系列之金蝶K3(三)

NewJune發表於2022-03-31

  小爬在之前的兩篇文章 【python辦公自動化系列之金蝶K3自動登入(一)】、【python辦公自動化系列之金蝶K3自動登入(二)】帶大家系統搞定了K3客戶端的自動登入難題,但是搞定【自動登入】只是我們軟體自動化的第一步,我們還要搞定之後的傳參、下載報表資料、切換賬號登入等一系列實際的業務問題。

  由於K3軟體在開發過程中,使用了大量自繪製的元件、控制元件,這些控制元件都無法通過SPY++或者Inspect等軟體檢測到,使得我們苦心學習的FindWindow、SendMessage等一系列win32API語法都失去了戰鬥力和用武之地。舉個例子,看下圖:

 

  假如我們想要下載【科目餘額表】,則登入賬套後,我們需要陸續滑鼠左鍵單擊主控臺對應的【財務會計】、【總賬】、【財務報表】,最後滑鼠左鍵雙擊【01016 科目餘額表】元素,才能進入【科目餘額表】報表介面,而上面的這些元素都是ThunderRT6PictureBoxDC 類,看到類名中有picture關鍵字,其實你就該放棄FindWindow來定位這種元素的想法了。

 

 

   我們可以怎麼做呢?一種方法是小爬後續要重點講到的【基於圖片識別元素並點選】,不過這裡我更想講講另外一個討巧的辦法。

K3的每個報表都有助記碼,類似於SAP的T-CODE。比如此處的【科目餘額表】報表,其助記碼就是01016,我們可以通過K3提供的助記碼查詢功能快速到達報表介面,如下圖(見K3主介面右上角):

 

   我們如果可以定點陣圖中的textBox控制元件,對其賦值:助記碼,然後模擬傳送【回車】,一樣可以開啟對應的報表,顯然這條路快速且可行:

 

   有了思路,程式碼只是水到渠成的事兒,小爬下面的程式碼示例供參考:

 1 def sendAssistCode(mainK3Hwnd,assistCode):
 2     '''假定已經找到K3主介面的控制程式碼且作為入口引數,然後找到助記碼視窗,傳送特定助記碼,直接去對應的功能報表'''
 3     assistCodeHwnd=0
 4     while assistCodeHwnd==0:
 5         time.sleep(0.2)
 6         ''''''
 7         ABSActiveBarDockHWnd=win32gui.FindWindowEx(mainK3Hwnd,0,"ABSActiveBarDockWnd","DockTop")
 8         ThunderRT6PictureBoHwnd1=win32gui.FindWindowEx(ABSActiveBarDockHWnd,0,"ThunderRT6PictureBoxDC","")
 9         ThunderRT6PictureBoHwnd2=win32gui.FindWindowEx(ABSActiveBarDockHWnd,ThunderRT6PictureBoHwnd1,"ThunderRT6PictureBoxDC","")
10         assistCodeHwnd=win32gui.FindWindowEx(ThunderRT6PictureBoHwnd2,0,"ThunderRT6TextBox","")
11     '''在k3主介面輸入助記碼並登入特定報表窗'''
12     win32gui.SendMessage(assistCodeHwnd, win32con.WM_SETTEXT, None,assistCode) 
13     win32gui.PostMessage(assistCodeHwnd, win32con.WM_KEYDOWN, win32con.VK_RETURN, 0)
14     time.sleep(0.01)
15     win32gui.PostMessage(assistCodeHwnd, win32con.WM_KEYUP, win32con.VK_RETURN, 0) 

  進入報表介面後,K3會彈出【過濾條件】視窗,等待使用者輸入條件,以便載入符合條件的報表資料,以【科目餘額表】的過濾條件為例,如下圖:

 

   經過SPY++捕獲不難發現,該介面的所有元素基本都是winform元件,可以用win32gui庫來搞定其傳參和自動化操作,不過其過程相對複雜,需要逐一去捕獲並操作,閒話少說,小爬直接上示例程式碼:

 1 def subjectBalanceFilter(conditionFlag1,conditionFlag2,conditionFlag3,conditionFlag4,conditionFlag5,
 2     conditionFlag6,conditionFlag7,conditionFlag8,subjectLevel,subjectYearFrom,subjectMonthFrom,subjectYearTo,subjectMonthTo):
 3     '''設定科目餘額表過濾條件,等待不超過10秒,捕獲【過濾條件】視窗,如果仍未出現,可能是出現了【異常彈窗】'''
 4     filterConditionHwnd=0
 5     while filterConditionHwnd==0:
 6         time.sleep(0.3)
 7         filterConditionHwnd=win32gui.FindWindow('ThunderRT6FormDC',"過濾條件")
 8     IsWindowVisible=0    
 9     while IsWindowVisible==0:
10         time.sleep(0.3)
11         filterConditionHwnd=win32gui.FindWindow('ThunderRT6FormDC',"過濾條件")
12         IsWindowVisible=win32gui.IsWindowVisible(filterConditionHwnd)
13     print("已找到【科目餘額表】過濾條件視窗")
14     time.sleep(0.5)
15     subjectLevelHwnd=0
16     while subjectLevelHwnd==0:
17         time.sleep(0.3)
18         userControlDcHwnd=win32gui.FindWindowEx(filterConditionHwnd,0,"ThunderRT6UserControlDC", None) # ThunderRT6UserControlDC
19         condition1Hwnd=win32gui.FindWindowEx(userControlDcHwnd,0,"ThunderRT6CheckBox", "顯示核算專案明細") # 顯示核算專案明細 checkBox
20         condition2Hwnd=win32gui.FindWindowEx(userControlDcHwnd,0,"ThunderRT6CheckBox", "包括未過賬憑證") # 包括未過賬憑證 checkBox
21         condition3Hwnd=win32gui.FindWindowEx(userControlDcHwnd,0,"ThunderRT6CheckBox", "包括餘額為零的科目") # 包括未過賬憑證 checkBox
22         condition4Hwnd=win32gui.FindWindowEx(userControlDcHwnd,0,"ThunderRT6CheckBox", "包括餘額借貸方合計") # 包括未過賬憑證 checkBox
23         condition5Hwnd=win32gui.FindWindowEx(userControlDcHwnd,0,"ThunderRT6CheckBox", "包括沒有業務發生的科目(期初、本年累計)") # 包括未過賬憑證 checkBox
24         condition6Hwnd=win32gui.FindWindowEx(userControlDcHwnd,0,"ThunderRT6CheckBox", "包括本期沒有發生額的科目") # 包括未過賬憑證 checkBox
25         condition7Hwnd=win32gui.FindWindowEx(userControlDcHwnd,0,"ThunderRT6CheckBox", "包括本年沒有發生額的科目") # 包括未過賬憑證 checkBox
26         condition8Hwnd=win32gui.FindWindowEx(userControlDcHwnd,0,"ThunderRT6CheckBox", "顯示禁用科目") # 包括未過賬憑證 checkBox
27         AdvancedBtn=win32gui.FindWindowEx(userControlDcHwnd,0,"ThunderRT6CommandButton", "高階>>") # 高階按鈕
28         accountingPeriodPreviousHwnd=win32gui.FindWindowEx(userControlDcHwnd,0,"ThunderRT6Frame", None) # 憑證期間
29         accountingPeriodHwnd=win32gui.FindWindowEx(userControlDcHwnd,accountingPeriodPreviousHwnd,"ThunderRT6Frame", None) # 憑證期間
30         parentYearFromHwnd=win32gui.FindWindowEx(accountingPeriodHwnd,0,"ThunderRT6UserControlDC", None) # YearFrom
31         yearFromHwnd=win32gui.FindWindowEx(parentYearFromHwnd,0,"ThunderRT6TextBox", None) # YearFrom
32         parentMonthToHwnd=win32gui.FindWindowEx(accountingPeriodHwnd,parentYearFromHwnd,"ThunderRT6UserControlDC", None) # MonthTo
33         monthToHwnd=win32gui.FindWindowEx(parentMonthToHwnd,0,"ThunderRT6TextBox", None) # MonthTo
34         parentMonthFromHwnd=win32gui.FindWindowEx(accountingPeriodHwnd,parentMonthToHwnd,"ThunderRT6UserControlDC", None) # MonthFrom
35         monthFromHwnd=win32gui.FindWindowEx(parentMonthFromHwnd,0,"ThunderRT6TextBox", None) # MonthFrom
36         parentYearToHwnd=win32gui.FindWindowEx(accountingPeriodHwnd,parentMonthFromHwnd,"ThunderRT6UserControlDC", None) # YearTo
37         yearToHwnd=win32gui.FindWindowEx(parentYearToHwnd,0,"ThunderRT6TextBox", None) # YearTo
38         granpaSubjectLevelHwnd=win32gui.FindWindowEx(userControlDcHwnd,accountingPeriodHwnd,"ThunderRT6Frame", None) # 科目級別
39         parentSubjectLevelHwnd=win32gui.FindWindowEx(granpaSubjectLevelHwnd,0,"ThunderRT6UserControlDC", None) # 科目級別
40         subjectLevelHwnd=win32gui.FindWindowEx(parentSubjectLevelHwnd,0,"ThunderRT6TextBox", None) # 科目級別
41     print("已找到【科目餘額表】過濾條件下各個控制元件元素")
42     '''點選 高階,展開更多checkbox項'''
43     time.sleep(0.2)
44     win32gui.SendMessage(AdvancedBtn,win32con.BM_CLICK,0,0) 
45     time.sleep(0.1)
46     conditionHwndDic={condition1Hwnd:conditionFlag1,condition2Hwnd:conditionFlag2,condition3Hwnd:conditionFlag3,condition4Hwnd:conditionFlag4,
47                     condition5Hwnd:conditionFlag5,condition6Hwnd:conditionFlag6,condition7Hwnd:conditionFlag7,condition8Hwnd:conditionFlag8} # 字典,key是conditionHwnd,value則是對應的checkbox狀態,為布林值
48     time.sleep(0.2)
49 
50     '''根據checkbox配置,設定K3對應各個checkbox值'''
51     for conditionHwnd in conditionHwndDic:
52         conditionFlag=conditionHwndDic[conditionHwnd]
53         currentCheckFlag=win32gui.SendMessage(conditionHwnd, win32con.BM_GETCHECK) # 顯示K3系統當前特定checkbox的布林值
54         while currentCheckFlag!=conditionFlag:
55             time.sleep(0.2)
56             win32gui.PostMessage(conditionHwnd, win32con.BM_SETCHECK, conditionFlag,0)
57             time.sleep(0.1)
58             currentCheckFlag=win32gui.SendMessage(conditionHwnd, win32con.BM_GETCHECK) # 顯示K3系統當前特定checkbox的布林值
59             
60     win32gui.SendMessage(subjectLevelHwnd, win32con.WM_SETTEXT, None,subjectLevel) # 設定科目級別    
61     time.sleep(0.3)
62     win32api.SendMessage(yearFromHwnd, win32con.WM_SETTEXT, None,subjectYearFrom)
63     time.sleep(0.2)
64     win32api.SendMessage(monthFromHwnd, win32con.WM_SETTEXT, None,subjectMonthFrom)
65     time.sleep(0.2)
66     win32api.SendMessage(yearToHwnd, win32con.WM_SETTEXT, None,subjectYearTo)
67     time.sleep(0.2)
68     win32api.SendMessage(monthToHwnd, win32con.WM_SETTEXT, None,subjectMonthTo)
69     time.sleep(0.2)
70 
71     '''給過濾條件視窗傳送回車,代表確定'''
72     time.sleep(1)
73     okBtnHwnd=win32gui.FindWindowEx(filterConditionHwnd,0,"ThunderRT6CommandButton","確定")
74     win32gui.PostMessage(okBtnHwnd,win32con.BM_CLICK,0,0)

  有了這些,距離我們玩轉金蝶K3的自動化就又前進了一大步。

歡迎掃碼關注我的公眾號 獲取更多爬蟲、資料分析的知識!

 

相關文章