python办公自动化系列之金蝶K3(三)
小爬在之前的两篇文章 【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的自动化就又前进了一大步。
欢迎扫码关注我的公众号 获取更多爬虫、数据分析的知识!

python办公自动化系列之金蝶K3(三)的更多相关文章
- python办公自动化系列之金蝶K3自动登录(二)
接上一篇博文python办公自动化系列之金蝶K3自动登录(一),我们接着聊聊利用python脚本实现金蝶K3 Wise客户端自动登录这一需求. 如上图所示,自动选择[组织机构]后,我们还需要驱动[当前 ...
- python办公自动化系列之金蝶K3自动登录(一)
做办公自动化的小伙伴都知道,驱动SAP GUI我们有SAP原生提供的[脚本录制与回放]以及SAP Scripting API可参考:驱动Office Excel等,我们有微软提供的[录制宏]功能:驱动 ...
- Python学习系列(三)(字符串)
Python学习系列(三)(字符串) Python学习系列(一)(基础入门) Python学习系列(二)(基础知识) 一个月没有更新博客了,最近工作上有点小忙,实在是没有坚持住,丢久又有感觉写的必要了 ...
- Python学习系列(四)Python 入门语法规则2
Python学习系列(四)Python 入门语法规则2 2017-4-3 09:18:04 编码和解码 Unicode.gbk,utf8之间的关系 2.对于py2.7, 如果utf8>gbk, ...
- 金蝶K3 wise 插件二次开发与配置
金蝶K3 wise 插件二次开发与配置 开发环境:K/3 Wise 13.0.K/3 Bos开发平台.Visual Basic 6.0 目录 一.二次开发插件编程二.代码演示三.配置插件四.测试插件五 ...
- JavaScript 系列博客(三)
JavaScript 系列博客(三) 前言 本篇介绍 JavaScript 中的函数知识. 函数的三种声明方法 function 命令 可以类比为 python 中的 def 关键词. functio ...
- 【转】python模块分析之typing(三)
[转]python模块分析之typing(三) 前言:很多人在写完代码一段时间后回过头看代码,很可能忘记了自己写的函数需要传什么参数,返回什么类型的结果,就不得不去阅读代码的具体内容,降低了阅读的速度 ...
- python模块分析之typing(三)
前言:很多人在写完代码一段时间后回过头看代码,很可能忘记了自己写的函数需要传什么参数,返回什么类型的结果,就不得不去阅读代码的具体内容,降低了阅读的速度,加上Python本身就是一门弱类型的语言,这种 ...
- python基础系列教程——Python的安装与测试:python的IDE工具PyDev和pycharm,anaconda
---恢复内容开始--- python基础系列教程——Python的安装与测试:python的IDE工具PyDev和pycharm,anaconda 从头开启python的开发环境搭建.安装比较简单, ...
随机推荐
- 【windows 访问控制】一、访问令牌
访问令牌(Access tokens) 访问令牌是描述进程或线程的安全上下文的对象.令牌中的信息包括与进程或线程关联的用户帐户的标识和特权信息.当用户登录时,系统通过将用户密码与安全数据库(如域认证中 ...
- 常见三种存储方式DAS、NAS、SAN的架构及比较
转至:https://blog.csdn.net/shipeng1022/article/details/72862367 随着主机.磁盘.网络等技术的发展,数据存储的方式和架构也在一直不停改变,本文 ...
- c# TextBox只能输入数字的处理方法(完整版各种情况考虑在内,可根据需求灵活修改)
//选择文本框的事件窗口,找到按键输入的方法KeyPress,双击建立新的方法. /// <summary> /// textBox只能输入数字的处理方法 /// </summary ...
- sprintf的用法总结
大概知道sprintf的用法,今天在CSDN上看到一篇关于sprintf比较好的总结,现在抄下来,emmmmmmm....... srpintf()函数的功能非常强大:效率比一些字符串操作函数要高:而 ...
- WPF优秀组件推荐之LiveCharts
概述 LiveCharts是一个比较漂亮的WPF图表控件,在数据变化时还会有动画切换的效果,并且样式也可以控制. 官方网站:Live Charts (lvcharts.net) 开源代码:GitHub ...
- C++_Leecode1 两数之和
一.题目介绍 1.题目描述 ->给定一个整数数组nums和一个整数目标值target,请你在该数组中找出和为目标值的那两个整数,并返回它们的数组下标. ->你可以假设每种输入只会对应一个答 ...
- jmeter + tomcat + ant + svn +jenkins 实现持续集成测试
l 安装jdk时候需要提前检查jdk是否安装成功 l 在dos下输入javac java -version l l 安装jmeter l 校验是否安装成功: l 进入jmeter目录下bin ...
- 从刘维尔方程到Velocity-Verlet算法
技术背景 我们说分子动力学模拟是一个牛顿力学的过程,在使用量子化学的手段或者深度学习的方法或者传统的力场方法,去得到某个时刻某个位置的受力之后,就可以获取下一步的整个系统的状态信息.这个演化的过程所使 ...
- RENIX板卡V2-100G系列工作模式速率切换——网络测试仪实操
本文主要介绍了RENIX板卡V2-100G系列工作模式速率切换相关操作.全文分为五部分内容.文章开头对V2-100G系列板卡进行了概述,之后分别详细介绍了100G工作模式.40G工作模式.25G工作模 ...
- Docker 学习之命令篇
Docker 学习之命令篇 1. docker images //镜像列表 2. docker ps –a //所有运行过的容器 3. docker ps –l 最后运行的容器 4. docker ...