• 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的自动化就又前进了一大步。

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

     

  • 相关阅读:
    SSL证书有效期
    面试官:请分析一条SQL的执行
    SpringBoot 根据不同环境切换不同文件路径
    iMazing2023最新版本下载及使用教程
    SQLite 3.43 发布,性能大提升!
    win10+ubuntu双系统下载ubuntu方法(卸载系统不完整会进入grub)
    visual studio Python 配置QGIS(qgis)教程
    【eCharts】第一部分 eCharts的准备工作
    萌新训练赛(1)
    【Java】RestClient的使用
  • 原文地址:https://www.cnblogs.com/new-june/p/16082970.html