python办公自动化系列之金蝶K3自动登录(二)
Python微信訂餐小程序課程視頻
https://edu.csdn.net/course/detail/36074
Python實(shí)戰(zhàn)量化交易理財(cái)系統(tǒng)
https://edu.csdn.net/course/detail/35475
接上一篇博文python辦公自動(dòng)化系列之金蝶K3自動(dòng)登錄(一),我們接著聊聊利用python腳本實(shí)現(xiàn)金蝶K3 Wise客戶端自動(dòng)登錄這一需求。
如上圖所示,自動(dòng)選擇【組織機(jī)構(gòu)】后,我們還需要驅(qū)動(dòng)【當(dāng)前賬套】、【命名用戶身份登錄】、【用戶名】、【密碼】、【確定】這幾個(gè)控件,才算是完成了K3 UI自動(dòng)化的第一步:自動(dòng)登錄。
一、設(shè)置【當(dāng)前賬套】控件
【當(dāng)前賬套】Label右邊對(duì)應(yīng)的同樣是一個(gè)ThunderRT6ComboBox 類,我們選擇comboBox某個(gè)下拉項(xiàng)時(shí),只有基于索引Index,但是由于集團(tuán)公司隨著業(yè)務(wù)不斷變化,賬套數(shù)可能存在變化,每個(gè)公司賬套對(duì)應(yīng)的索引值也會(huì)變化。因此,我們最好想辦法實(shí)現(xiàn)基于賬套名稱來實(shí)現(xiàn)驅(qū)動(dòng)某個(gè)comboBox控件。比較通俗易懂的做法是,我們先設(shè)法拿到這個(gè)組件的所有l(wèi)istItem,將每個(gè)Item對(duì)應(yīng)的value(文本值)和listIndex(索引)存入一個(gè)字典,那么當(dāng)用戶端隨便拋給我們一個(gè)賬套名時(shí),我們便能基于該字典迅速知道listIndex,再基于它來選擇這個(gè)comboBox控件。這里面涉及到comboBox一些屬性和方法的應(yīng)用,具體示例代碼如下:
1 import win32gui,win32con2 def getAccountDic(currentAccountHwnd):3 '''根據(jù)【當(dāng)前賬套】的句柄,得到該comboBox所有下拉選項(xiàng),將選項(xiàng)值ItemText和對(duì)應(yīng)的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 # 創(chuàng)建一個(gè)比combobox 文本長度兩倍的buffer,確保數(shù)據(jù)都能存進(jìn)去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() # 從內(nèi)存中取出combobox的當(dāng)前項(xiàng)內(nèi)容 13 accountDic[itemText]=i 14 return accountDic 15 16 def setCurrentAccount(currentAccountHwnd,currentAccountName,accountDic): 17 '''根據(jù)【當(dāng)前賬套】的句柄,,需要選擇的賬套名稱,和賬套字典,選擇特定賬套為當(dāng)前賬套''' 18 accountIndex=accountDic[currentAccountName] 19 win32gui.SendMessage(currentAccountHwnd, win32con.CB\_SETCURSEL, accountIndex, 0)二、選擇【登錄方式】為【以命名用戶身份登錄(D)】
根據(jù)實(shí)際需要,小爬這里演示下以命名用戶身份登錄(D),其它登錄方式,手段同理。spy++觀察到它其實(shí)是一個(gè)optionButton。我們可以這樣設(shè)置:
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) # 設(shè)置登錄方式為【以命名用戶身份登錄(D)】 6 time.sleep(0.01) 7 win32gui.SendMessage(optionBtnHandle, win32con.WM\_LBUTTONUP, 0, 0)三、設(shè)置【用戶名】、【密碼】控件
通過spy++觀察到這兩個(gè)控件的類名為ThunderRT6TextBox,也算是textBox的子類。我們可以大膽使用SendMessage的WM_SETTEXT來實(shí)現(xiàn)這一點(diǎn),唯一的難度在于基于類名來定位這兩個(gè)控件時(shí)稍微有些麻煩,其中【密碼框】控件可以通過定位父元素,然后利用findwindowEx方法,基于ThunderRT6TextBox找到第一個(gè)元素即可,而【用戶名框】可以通過【當(dāng)前賬套】控件來找下一個(gè)控件得到。這里比較讓人混淆的是:后臺(tái)的所有控件【用戶名】在下,【密碼】在上,與肉眼觀察到的物理位置剛好相反。具體代碼示例如下:
1 def setUserInfo(userName,passWord,parentHwnd,currentAccountHwnd): 2 passwordHwnd=win32gui.FindWindowEx(parentHwnd,0,"ThunderRT6TextBox", None) # 密碼框,基于父元素和其類名找到的第一個(gè)即可 3 time.sleep(0.1) 4 userNameHwnd=win32gui.FindWindowEx(parentHwnd,currentAccountHwnd,None, None) # 用戶名框,基于【當(dāng)前賬套】控件句柄找到下一個(gè)即可 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)四、發(fā)送【回車】實(shí)現(xiàn)登錄
小爬通過模擬給登錄界面發(fā)送【回車鍵】來實(shí)現(xiàn)登錄,示例代碼如下:
1 '''根據(jù)登錄界面句柄sysLoginWnd,發(fā)送回車鍵實(shí)現(xiàn)登錄''' 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)結(jié)合上一篇博文,我們基本就完成了K3登錄需要的各個(gè)方法,我們只需要依次調(diào)用,就可以實(shí)現(xiàn)K3自動(dòng)登錄某個(gè)賬套啦。希望小爬的分享對(duì)你們的日常工作有所幫助,完整代碼如下,供參考,:
1 # 需要使用管理員權(quán)限運(yùn)行VScode或者Pycharm,否則無法正常使用2 import win32gui,win32api,win32con,subprocess,time,os3 def getK3LoginHwnd():4 sysLoginWnd=win32gui.FindWindow('ThunderRT6Form',"金蝶K/3系統(tǒng)登錄") # K3系統(tǒng)登錄窗5 if sysLoginWnd==0:6 subprocess.Popen(r'C:\Program Files (x86)\Kingdee\K3ERP\K3MainNet.exe')7 8 # subprocess發(fā)送指令啟動(dòng)后需要等K3登錄窗徹底可見后,再進(jìn)行后續(xù)操作9 while sysLoginWnd==0: 10 time.sleep(0.3) 11 sysLoginWnd=win32gui.FindWindow('ThunderRT6Form',"金蝶K/3系統(tǒng)登錄") # K3系統(tǒng)登錄窗 12 isSysLoginWndVisible=0 13 while isSysLoginWndVisible==0: 14 time.sleep(0.3) 15 sysLoginWnd=win32gui.FindWindow('ThunderRT6Form',"金蝶K/3系統(tǒng)登錄") # K3系統(tǒng)登錄窗 16 isSysLoginWndVisible=win32gui.IsWindowVisible(sysLoginWnd) # 判斷窗口是否已經(jīng)對(duì)用戶可見 17 return sysLoginWnd 18 19 def setOrganization(sysLoginWnd,organizationIndex): 20 '''根據(jù)K3登錄窗的句柄sysLoginWnd和下拉框索引值organizationIndex,選擇特定的組織機(jī)構(gòu)''' 21 mainHwnd1=win32gui.FindWindowEx(sysLoginWnd,0,None, '') # ThunderRT6PictureBoxDC 22 mainHwnd2=win32gui.FindWindowEx(sysLoginWnd,mainHwnd1,None, '') # ThunderRT6PictureBoxDC 23 organizationHwnd=win32gui.FindWindowEx(mainHwnd2,0,"ThunderRT6ComboBox", '') # 組織機(jī)構(gòu) 24 currentOrgIndex=win32gui.SendMessage(organizationHwnd, win32con.CB\_GETCURSEL) # 當(dāng)前combobox選中的index 25 if currentOrgIndex!=organizationIndex: 26 win32gui.SendMessage(organizationHwnd, win32con.CB\_SETCURSEL, organizationIndex, 0) 27 28 '''模擬鼠標(biāo)左鍵點(diǎn)擊元素,激活它''' 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 '''小爬此處的場景中,【組織機(jī)構(gòu)】有6個(gè)下拉項(xiàng),那么最大的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 '''根據(jù)【當(dāng)前賬套】的句柄,得到該comboBox所有下拉選項(xiàng),將選項(xiàng)值ItemText和對(duì)應(yīng)的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 # 創(chuàng)建一個(gè)比combobox 文本長度兩倍的buffer,確保數(shù)據(jù)都能存進(jìn)去 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() # 從內(nèi)存中取出combobox的當(dāng)前項(xiàng)內(nèi)容 63 accountDic[itemText]=i 64 return accountDic 65 66 def setCurrentAccount(currentAccountHwnd,currentAccountName,accountDic): 67 '''根據(jù)【當(dāng)前賬套】的句柄,,需要選擇的賬套名稱,和賬套字典,選擇特定賬套為當(dāng)前賬套''' 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) # 設(shè)置登錄方式為【以命名用戶身份登錄(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) # 密碼框,基于父元素和其類名找到的第一個(gè)即可 81 time.sleep(0.1) 82 userNameHwnd=win32gui.FindWindowEx(parentHwnd,currentAccountHwnd,None, None) # 用戶名框,基于【當(dāng)前賬套】控件句柄找到下一個(gè)即可 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 '''根據(jù)登陸界面句柄sysLoginWnd,發(fā)送回車鍵實(shí)現(xiàn)登錄''' 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)歡迎掃碼關(guān)注我的公眾號(hào) 獲取更多爬蟲、數(shù)據(jù)分析的知識(shí)!
總結(jié)
以上是生活随笔為你收集整理的python办公自动化系列之金蝶K3自动登录(二)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: html侧边导航栏折叠,HTML侧面导航
- 下一篇: 一行代码告诉你为什么python代码中要