接上一篇博文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)

欢迎扫码关注我的公众号 获取更多爬虫、数据分析的知识!

python办公自动化系列之金蝶K3自动登录(二)的更多相关文章

  1. python办公自动化系列之金蝶K3自动登录(一)

    做办公自动化的小伙伴都知道,驱动SAP GUI我们有SAP原生提供的[脚本录制与回放]以及SAP Scripting API可参考:驱动Office Excel等,我们有微软提供的[录制宏]功能:驱动 ...

  2. python办公自动化系列之金蝶K3(三)

    小爬在之前的两篇文章 [python办公自动化系列之金蝶K3自动登录(一)].[python办公自动化系列之金蝶K3自动登录(二)]带大家系统搞定了K3客户端的自动登录难题,但是搞定[自动登录]只是我 ...

  3. 金蝶K3 wise 插件二次开发与配置

    金蝶K3 wise 插件二次开发与配置 开发环境:K/3 Wise 13.0.K/3 Bos开发平台.Visual Basic 6.0 目录 一.二次开发插件编程二.代码演示三.配置插件四.测试插件五 ...

  4. python网络爬虫之使用scrapy自动登录网站

    前面曾经介绍过requests实现自动登录的方法.这里介绍下使用scrapy如何实现自动登录.还是以csdn网站为例. Scrapy使用FormRequest来登录并递交数据给服务器.只是带有额外的f ...

  5. python带cookie提交表单自动登录(转)

    今天突然把博客给申请了,以前也想过的,奈于自己觉得水平还太低有点不好意思写博客,但是后来一想,自己的记录所学,加深印象,主要还是为了学习进步,不怕丢人!今天就稍微回顾一下这两天写的一段用python模 ...

  6. 使用Python定时执行一任务,自动登录某web系统,生成报表,然后发送邮件给指定人员

    一.项目需求 每周从A系统生成一张Excel报表,发送此报表给指定人员,相关人员依据此报表去完成后续的工作. 项目限制: 1.无法通过EDI系统交互的方式从后台读取数据 2.由于公司网络环境限制,不能 ...

  7. python带cookie提交表单自动登录

    import urllib import urllib2 import cookielib login_url = "xxxxxxxxxxxxx" cj = cookielib.C ...

  8. Appium python自动化测试系列之appium环境搭建(二)

    ​2.1 基础环境搭建 当我们学习新的一项技术开始基本都是从环境搭建开始,本书除了第一章节也是的,如果你连最基础的环境都没有那么我们也没必要去说太多,大概介绍一下: 1.因为appium是支持andr ...

  9. Appium python自动化测试系列之日志的收集(十二)

    ​13.1 日志的定义 13.1.1 日志的定义 听到日志这个东西可能有的人莫名其妙,第一次接触就会觉得我们为什么要收集日志,即使要收集日志那么我们需要收集哪些日志,日志的作用是什么等等. 其实日志无 ...

随机推荐

  1. Zookeeper基础教程(五):C#实现Zookeeper分布式锁

    分布式锁 互联网初期,我们系统一般都是单点部署,也就是在一台服务器完成系统的部署,后期随着用户量的增加,服务器的压力也越来越大,响应速度越来越慢,甚至出现服务器崩溃的情况. 为解决服务器压力太大,响应 ...

  2. shell2-if判断

    1.条件测试类型(判断类型): 将测试结果做为判断依据. 测试类型有以下三种   [ 命令 ] :命令测试法(最常用的)  [[ 命令 ]] : 关键字测试 test 命令 以上是三种都可以,注意单词 ...

  3. 第三代微服务架构:基于 Go 的博客微服务实战案例,支持分布式事务

    这是一个可一键部署在 Kubernetes-Istio 集群中的,基于 Golang 的博客微服务 Demo,支持分布式事务. 项目地址:https://github.com/jxlwqq/blog- ...

  4. CentOS6.5下安装Hadoop-2.7.3(图解教程)

    注:图片如果损坏,点击文章链接:https://www.toutiao.com/i6627365258090512909/ 已安装好虚拟机(3个节点) YUM源已安装好.系统版本CentOS6.5.j ...

  5. 手动安装selenium包

    1.下载selenium安装包 https://pypi.org/project/selenium 2.解压selenium-3.12.0.tar.gz 3.cmd环境进入到selenium的setu ...

  6. CAS学习笔记四:CAS单点登出流程

    CAS 的登出包含两种情况,一种是CAS客户端登出,另一种是CAS单点登出,使用流程图说明这两者的不同.(一图胜千言) 总结自官方文档 CAS客户端登出流程 如图,客户端的登出仅仅是过期当前用户与客户 ...

  7. 【get√】golang新手理解了一点点context

    测试代码如下: package practice import ( "context" "log" //"fmt" "time&q ...

  8. WebGPU相关的资源学习和社区

    我在网上搜寻了很多关于WebGPU相关的资料: #我觉得首先在B站上看到的徐博士免费教程非常好,讲解详细,并且评论回复比较快,都会有回应,徐博士B站网址:https://space.bilibili. ...

  9. AOP操作-准备工作

    AOP操作(准备) 1,Spring 框架中一般基于 AspectJ 实现AOP操作 (1)什么是 AspectJ *AspectJ 不是 Spring 组成部分,独立AOP框架,一般把 Aspect ...

  10. IoC容器-Bean管理XML方式(注入空值和特殊符号)

    Ioc操作Bean管理(xml注入其他类型属性), 字面量 (1)null值 (2)属性值包含特殊符号