python辦公自動化系列之金蝶K3自動登錄(二) python辦公自動化系列之金蝶K3自動登錄(一)

  接上一篇博文python辦公自動化系列之金蝶K3自動登錄(一),我們接着聊聊利用python腳本實現金蝶K3 Wise客戶端自動登錄這一需求。

 

 

   如上圖所示,自動選擇【組織機構】後,我們還需要驅動【當前賬套】、【命名用戶身份登錄】、【用戶名】、【密碼】、【確定】這幾個控件,纔算是完成了K3 UI自動化的第一步:自動登錄。

一、設置【當前賬套】控件

  【當前賬套】Label右邊對應的同樣是一個ThunderRT6ComboBox 類,我們選擇comboBox某個下拉項時,只有基於索引Index,但是由於集團公司隨着業務不斷變化,賬套數可能存在變化,每個公司賬套對應的索引值也會變化。因此,我們最好想辦法實現基於賬套名稱來實現驅動某個comboBox控件。比較通俗易懂的做法是,我們先設法拿到這個組件的所有listItem,將每個Item對應的value(文本值)和listIndex(索引)存入一個字典,那麼當用戶端隨便拋給我們一個賬套名時,我們便能基於該字典迅速知道listIndex,再基於它來選擇這個comboBox控件。這裏面涉及到comboBox一些屬性和方法的應用,具體示例代碼如下:

 1 import win32gui,win32con
 2 def getAccountDic(currentAccountHwnd):
 3     '''根據【當前賬套】的句柄,得到該comboBox所有下拉選項,將選項值ItemText和對應的ItemIndex存入字典 accountDic,最終返回'''
 4     accountDic={}
 5     accountCnt=win32gui.SendMessage(currentAccountHwnd, win32con.CB_GETCOUNT, 0, 0)
 6     for i in range(accountCnt):
 7         textLen= win32gui.SendMessage(currentAccountHwnd, win32con.CB_GETLBTEXTLEN, i,0)*2 # 創建一個比combobox 文本長度兩倍的buffer,確保數據都能存進去
 8         buffer = win32gui.PyMakeBuffer(textLen)
 9         win32gui.SendMessage(currentAccountHwnd, win32con.CB_GETLBTEXT, i, buffer)
10         address,length=win32gui.PyGetBufferAddressAndLen(buffer[:-1])
11         length=int((length+1)/2) 
12         itemText=win32gui.PyGetString(address,length).strip()  # 從內存中取出combobox的當前項內容  
13         accountDic[itemText]=i
14     return accountDic
15 
16 def setCurrentAccount(currentAccountHwnd,currentAccountName,accountDic):
17     '''根據【當前賬套】的句柄,,需要選擇的賬套名稱,和賬套字典,選擇特定賬套爲當前賬套'''
18     accountIndex=accountDic[currentAccountName]
19     win32gui.SendMessage(currentAccountHwnd, win32con.CB_SETCURSEL, accountIndex, 0)

 

二、選擇【登錄方式】爲【以命名用戶身份登錄(D)】

  根據實際需要,小爬這裏演示下以命名用戶身份登錄(D),其它登錄方式,手段同理。spy++觀察到它其實是一個optionButton。我們可以這樣設置:

1 def setOptionBtn(parentHwnd,optionName):
2     # optionName="以命名用戶身份登錄(D)"
3     '''通過spy++得到這些optionButton的父元素句柄,在基於文本optionName找到並選擇特定的optionButton'''
4     optionBtnHandle=win32gui.FindWindowEx(parentHwnd,0,None, optionName) # 以命名用戶身份登錄(D) optionButton
5     win32gui.SendMessage(optionBtnHandle, win32con.WM_LBUTTONDOWN, 0, 0) # 設置登錄方式爲【以命名用戶身份登錄(D)】
6     time.sleep(0.01)
7     win32gui.SendMessage(optionBtnHandle, win32con.WM_LBUTTONUP, 0, 0)

 

三、設置【用戶名】、【密碼】控件

 

 

 

  通過spy++觀察到這兩個控件的類名爲ThunderRT6TextBox,也算是textBox的子類。我們可以大膽使用SendMessage的WM_SETTEXT來實現這一點,唯一的難度在於基於類名來定位這兩個控件時稍微有些麻煩,其中【密碼框】控件可以通過定位父元素,然後利用findwindowEx方法,基於ThunderRT6TextBox找到第一個元素即可,而【用戶名框】可以通過【當前賬套】控件來找下一個控件得到。這裏比較讓人混淆的是:後臺的所有控件【用戶名】在下,【密碼】在上,與肉眼觀察到的物理位置剛好相反。具體代碼示例如下:

1 def setUserInfo(userName,passWord,parentHwnd,currentAccountHwnd):
2     passwordHwnd=win32gui.FindWindowEx(parentHwnd,0,"ThunderRT6TextBox", None) # 密碼框,基於父元素和其類名找到的第一個即可
3     time.sleep(0.1)
4     userNameHwnd=win32gui.FindWindowEx(parentHwnd,currentAccountHwnd,None, None)  # 用戶名框,基於【當前賬套】控件句柄找到下一個即可
5     time.sleep(0.1)
6     win32gui.SendMessage(userNameHwnd, win32con.WM_SETTEXT, None,userName)
7     time.sleep(0.1)
8     win32gui.SendMessage(passwordHwnd, win32con.WM_SETTEXT, None,passWord)

四、發送【回車】實現登錄

  小爬通過模擬給登錄界面發送【回車鍵】來實現登錄,示例代碼如下:

1     '''根據登錄界面句柄sysLoginWnd,發送回車鍵實現登錄'''
2     win32gui.PostMessage(sysLoginWnd, win32con.WM_KEYDOWN, win32con.VK_RETURN, 0)
3     time.sleep(0.01)
4     win32gui.PostMessage(sysLoginWnd, win32con.WM_KEYUP, win32con.VK_RETURN, 0)

   結合上一篇博文,我們基本就完成了K3登錄需要的各個方法,我們只需要依次調用,就可以實現K3自動登錄某個賬套啦。希望小爬的分享對你們的日常工作有所幫助,完整代碼如下,供參考,:

 1 # 需要使用管理員權限運行VScode或者Pycharm,否則無法正常使用
 2 import win32gui,win32api,win32con,subprocess,time,os
 3 def getK3LoginHwnd():
 4     sysLoginWnd=win32gui.FindWindow('ThunderRT6Form',"金蝶K/3系統登錄") # K3系統登錄窗
 5     if sysLoginWnd==0:
 6         subprocess.Popen(r'C:\Program Files (x86)\Kingdee\K3ERP\K3MainNet.exe')
 7 
 8     # subprocess發送指令啓動後需要等K3登錄窗徹底可見後,再進行後續操作
 9     while sysLoginWnd==0:
10         time.sleep(0.3)
11         sysLoginWnd=win32gui.FindWindow('ThunderRT6Form',"金蝶K/3系統登錄") # K3系統登錄窗
12     isSysLoginWndVisible=0
13     while isSysLoginWndVisible==0:
14         time.sleep(0.3)
15         sysLoginWnd=win32gui.FindWindow('ThunderRT6Form',"金蝶K/3系統登錄") # K3系統登錄窗
16         isSysLoginWndVisible=win32gui.IsWindowVisible(sysLoginWnd) # 判斷窗口是否已經對用戶可見
17     return sysLoginWnd
18  
19 def setOrganization(sysLoginWnd,organizationIndex):
20     '''根據K3登錄窗的句柄sysLoginWnd和下拉框索引值organizationIndex,選擇特定的組織機構'''
21     mainHwnd1=win32gui.FindWindowEx(sysLoginWnd,0,None, '') # ThunderRT6PictureBoxDC
22     mainHwnd2=win32gui.FindWindowEx(sysLoginWnd,mainHwnd1,None, '') # ThunderRT6PictureBoxDC
23     organizationHwnd=win32gui.FindWindowEx(mainHwnd2,0,"ThunderRT6ComboBox", '') # 組織機構
24     currentOrgIndex=win32gui.SendMessage(organizationHwnd, win32con.CB_GETCURSEL) # 當前combobox選中的index
25     if currentOrgIndex!=organizationIndex:
26         win32gui.SendMessage(organizationHwnd, win32con.CB_SETCURSEL, organizationIndex, 0)
27 
28         '''模擬鼠標左鍵點擊元素,激活它'''
29         win32gui.SendMessage(organizationHwnd, win32con.WM_LBUTTONDOWN, 0, 0) 
30         time.sleep(0.01)
31         win32gui.SendMessage(organizationHwnd, win32con.WM_LBUTTONUP, 0, 0)
32 
33         '''小爬此處的場景中,【組織機構】有6個下拉項,那麼最大的index就是5'''
34         if organizationIndex<5: # 模擬鍵盤↓+鍵盤↑
35             win32gui.PostMessage(organizationHwnd, win32con.WM_KEYDOWN, win32con.VK_DOWN, 0)
36             time.sleep(0.01)
37             win32gui.PostMessage(organizationHwnd, win32con.WM_KEYUP, win32con.VK_DOWN, 0)
38             time.sleep(0.1)
39             win32gui.PostMessage(organizationHwnd, win32con.WM_KEYDOWN, win32con.VK_UP, 0)
40             time.sleep(0.01)
41             win32gui.PostMessage(organizationHwnd, win32con.WM_KEYUP, win32con.VK_UP, 0)
42         else: # 模擬鍵盤↑+鍵盤↓
43             win32gui.PostMessage(organizationHwnd, win32con.WM_KEYDOWN, win32con.VK_UP, 0)
44             time.sleep(0.01)
45             win32gui.PostMessage(organizationHwnd, win32con.WM_KEYUP, win32con.VK_UP, 0) 
46             time.sleep(0.1) 
47             win32gui.PostMessage(organizationHwnd, win32con.WM_KEYDOWN, win32con.VK_DOWN, 0)
48             time.sleep(0.01)
49             win32gui.PostMessage(organizationHwnd, win32con.WM_KEYUP, win32con.VK_DOWN, 0)
50             time.sleep(0.1)
51          
52 def getAccountDic(currentAccountHwnd):
53     '''根據【當前賬套】的句柄,得到該comboBox所有下拉選項,將選項值ItemText和對應的ItemIndex存入字典 accountDic,最終返回'''
54     accountDic={}
55     accountCnt=win32gui.SendMessage(currentAccountHwnd, win32con.CB_GETCOUNT, 0, 0)
56     for i in range(accountCnt):
57         textLen= win32gui.SendMessage(currentAccountHwnd, win32con.CB_GETLBTEXTLEN, i,0)*2 # 創建一個比combobox 文本長度兩倍的buffer,確保數據都能存進去
58         buffer = win32gui.PyMakeBuffer(textLen)
59         win32gui.SendMessage(currentAccountHwnd, win32con.CB_GETLBTEXT, i, buffer)
60         address,length=win32gui.PyGetBufferAddressAndLen(buffer[:-1])
61         length=int((length+1)/2) 
62         itemText=win32gui.PyGetString(address,length).strip()  # 從內存中取出combobox的當前項內容  
63         accountDic[itemText]=i
64     return accountDic
65 
66 def setCurrentAccount(currentAccountHwnd,currentAccountName,accountDic):
67     '''根據【當前賬套】的句柄,,需要選擇的賬套名稱,和賬套字典,選擇特定賬套爲當前賬套'''
68     accountIndex=accountDic[currentAccountName]
69     win32gui.SendMessage(currentAccountHwnd, win32con.CB_SETCURSEL, accountIndex, 0)
70 
71 def setOptionBtn(parentHwnd,optionName):
72     # optionName="以命名用戶身份登錄(D)"
73     '''通過spy++得到這些optionButton的父元素句柄,在基於文本optionName找到並選擇特定的optionButton'''
74     optionBtnHandle=win32gui.FindWindowEx(parentHwnd,0,None, optionName) # 以命名用戶身份登錄(D) optionButton
75     win32gui.SendMessage(optionBtnHandle, win32con.WM_LBUTTONDOWN, 0, 0) # 設置登錄方式爲【以命名用戶身份登錄(D)】
76     time.sleep(0.01)
77     win32gui.SendMessage(optionBtnHandle, win32con.WM_LBUTTONUP, 0, 0)
78 
79 def setUserInfo(userName,passWord,parentHwnd,currentAccountHwnd):
80     passwordHwnd=win32gui.FindWindowEx(parentHwnd,0,"ThunderRT6TextBox", None) # 密碼框,基於父元素和其類名找到的第一個即可
81     time.sleep(0.1)
82     userNameHwnd=win32gui.FindWindowEx(parentHwnd,currentAccountHwnd,None, None)  # 用戶名框,基於【當前賬套】控件句柄找到下一個即可
83     time.sleep(0.1)
84     win32gui.SendMessage(userNameHwnd, win32con.WM_SETTEXT, None,userName)
85     time.sleep(0.1)
86     win32gui.SendMessage(passwordHwnd, win32con.WM_SETTEXT, None,passWord)
87 
88 def sendReturn(sysLoginWnd):
89     '''根據登陸界面句柄sysLoginWnd,發送回車鍵實現登錄'''
90     win32gui.PostMessage(sysLoginWnd, win32con.WM_KEYDOWN, win32con.VK_RETURN, 0)
91     time.sleep(0.01)
92     win32gui.PostMessage(sysLoginWnd, win32con.WM_KEYUP, win32con.VK_RETURN, 0)

 

歡迎掃碼關注我的公衆號 獲取更多爬蟲、數據分析的知識!

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章