克米亚sap论坛,最好的sap论坛,sap系统,sap培训,kemiya,克米亚,sap账号,sap ides,sap mm,sap hana,sap fico,sap pp

 找回密码
 注册
查看: 202|回复: 0

Python驱动SAP GUI完成自动化(选择布局+动态获取节点值)

[复制链接]
kmy 发表于 2021-4-7 16:48:14 | 显示全部楼层 |阅读模式
讨论过如何利用工具Scripting Tracker录制python操纵SAP GUI的py脚本。软件的录制和生成的代码界面如下:
1412260-20200530181334920-1563426547.png



  场景一:实际业务中,除了一些常规步骤,我们可能会驱动SAP GUI中的一些布局,改变数据的展现形式,如:
1412260-20200531234401323-2126574797.png




  譬如这段点击“选择布局”,选中“/GX发出商品"布局的操作,我们用工具得到的python代码如下:
[url=] copycode.gif [/url]
    session.findById("wnd[0]/tbar[1]/btn[33]").press() # 点击”选择布局"按钮
    session.findById("wnd[1]/usr/ssubD0500_SUBSCREEN:SAPLSLVC_DIALOG:0501/cntlG51_CONTAINER/shellcont/shell").setCurrentCell(14, "TEXT") # 选中某个单元格
    session.findById("wnd[1]/usr/ssubD0500_SUBSCREEN:SAPLSLVC_DIALOG:0501/cntlG51_CONTAINER/shellcont/shell").firstVisibleRow = 3 # 驱动纵向滚动条
    session.findById("wnd[1]/usr/ssubD0500_SUBSCREEN:SAPLSLVC_DIALOG:0501/cntlG51_CONTAINER/shellcont/shell").selectedRows = "14" # 选中第15行
    session.findById("wnd[1]/usr/ssubD0500_SUBSCREEN:SAPLSLVC_DIALOG:0501/cntlG51_CONTAINER/shellcont/shell").clickCurrentCell()  # 单击选中的单元格

[url=] copycode.gif [/url]

  通过观察实际界面可知,我们要的“/GX发出商品"属于从上至下的第15个布局(索引号从0开始,因此这里的索引号应该是14),但是考虑到很多用户都有权限去设置布局或者变式,导致我们的自动化脚本如果直接以索引号来定位某个布局的做法,非常不稳定,易出错。更稳妥的做法是基于变式的“名称”,这个名称具备唯一性,哪怕将来有新增的布局,或者用户排版布局所用到的排序变了,我们依然可以通过布局的名称来定位它。
通过SAP GuiContainerShell的rowCount和visibleRowCount属性,可以分别得到该布局的shell对应的行数和 可见行数,我们遍历所有的行,然后根据 每个cell的getCellValue方法就能拿到布局的名称,最终找到相应的布局。代码就可以这样写:
[url=] copycode.gif [/url]
    session.findById("wnd[0]/tbar[1]/btn[33]").press() # 点击”选择布局"按钮    e=session.findById("wnd[1]/usr/ssubD0500_SUBSCREEN:SAPLSLVC_DIALOG:0501/cntlG51_CONTAINER/shellcont/shell")    row_count=e.rowCount    variant="" # 变式    for i in range(row_count):        variant=e.getCellValue(i,"VARIANT")        if variant=="/GX发出商品":            e.setCurrentCell(i, "VARIANT") # 选中某个单元格            e.clickCurrentCell()    if variant=="":        print("该布局中没有找到“/GX发出商品”变式,请核实!") [url=] copycode.gif [/url]

录制代码中以下这两行,在实际中,可以省略,不影响代码的执行:
    session.findById("wnd[1]/usr/ssubD0500_SUBSCREEN:SAPLSLVC_DIALOG:0501/cntlG51_CONTAINER/shellcont/shell").firstVisibleRow = 3 # 驱动纵向滚动条    session.findById("wnd[1]/usr/ssubD0500_SUBSCREEN:SAPLSLVC_DIALOG:0501/cntlG51_CONTAINER/shellcont/shell").selectedRows = "14" # 选中第15行

  场景二:实际业务中,我们可能会碰到这种行数不固定,节点可以逐级展开的sap 界面,我们又该如何取到对应节点对应字段的值呢?
1412260-20200530191004466-158085082.png


我们逐级展开节点到想要的位置,然后,选中某个值的过程,用tracker录制得到python代码,形式类如:
[url=] copycode.gif [/url]
session.findById("wnd[0]").resizeWorkingPane(234, 40, 0)session.findById("wnd[0]/shellcont/shell/shellcont[1]/shell[1]").expandNode("        339")session.findById("wnd[0]/shellcont/shell/shellcont[1]/shell[1]").expandNode("        576")session.findById("wnd[0]/shellcont/shell/shellcont[1]/shell[1]").expandNode("        608")session.findById("wnd[0]/shellcont/shell/shellcont[1]/shell[1]").expandNode("        612")session.findById("wnd[0]/shellcont/shell/shellcont[1]/shell[1]").expandNode("        613")session.findById("wnd[0]/shellcont/shell/shellcont[1]/shell[1]").selectItem("        614", "C          1")session.findById("wnd[0]/shellcont/shell/shellcont[1]/shell[1]").ensureVisibleHorizontalItem("        614", "C          1")session.findById("wnd[0]/shellcont/shell/shellcont[1]/shell[1]").topNode = "          2"[url=] copycode.gif [/url]

这结构,每一个cell可以看作是一个Item对象,我们可以用sap GUI Scripting API手册查到它的GetItemText方法:
1412260-20200530191928862-897914415.png


这里的Key 和Name就是上面录制得到的脚本中的("        614","C          1")形式:
  由于这种含可展开节点的SAP GUI界面,行数都是不确定的,为了一劳永逸,我们还是要先动态得到 key,再基于Key Name,依据getItemText方法,得到节点的名称,如果跟我们要的节点名一样,我们就可找到 对应节点的 其他字段的值。
于是关键问题演化成了,这个"        614"的key是怎么来的,我们大胆猜测,它就是一个变化的数字,前面填充空格,实际的几次试错后,小爬发现这个空格数不是固定的,而Key的长度是却固定的。
  所以,我们先用字符串的len("        614")方法得到key的长度为11,假如key中的数字 i 从1往1000(假定最大值不超过1000)变,我们可以计算其长度len(str(i)),来得到该填充的空格数,我们把整个界面用循环遍历一遍,接下来代码验证开始:
[url=] copycode.gif [/url]
    col1_value="";col2_value="";col3_value="";node_name=""    e=session.findById("wnd[0]/shellcont/shell/shellcont[1]/shell[1]")    for i in range(1,1000): # 这里如果不清楚具体有多少行,可以设置一个很大的数,最后break跳出循环即可        node_name = e.getItemText(" "*(11-len(str(i)))+str(i), "&Hierarchy")  # 索引号总共11位,除了数字,开头用多个空格符补齐,数字位数越大,则要补的空格越少        if node_name == "损益表":            col1_value=e.getItemText(" "*(11-len(str(i)))+str(i), "C          1")            col2_value=e.getItemText(" "*(11-len(str(i)))+str(i), "C          3")            col3_value=e.getItemText(" "*(11-len(str(i)))+str(i), "C          5")            # 我们要获取 含“存货变动”关键字的 科目的cmp金额        elif "存货变动" in node_name:            cmp_value=e.getItemText(" "*(11-len(str(i)))+str(i), "C          5")        if col1_value!="" and col2_value!="" and col3_value!="":            break[url=] copycode.gif [/url]

(更新日期:2020-05-31 :感谢评论区的童鞋友情提示,这段字符串右对齐,左边补空格的操作,python中有原生的字符串方法支持:str.rjust(width[, fillchar]),同样也有str.ljust(width[, fillchar])方法,上面代码中的的key可以用 str(i).rjust(11) 来快速得到……)
(更新日期:2020-05-31 :上面的代码中,假定的这个GUI Tree有1000个节点,这还不是最严谨的做法,实际上,我们如果想遍历这个tree的所有节点,只需要遍历所有的key,而SAP其实提供了这样的API来得到tree中所有的节点的key)
1412260-20200531232712330-599638958.png


于是上面的代码可以改为下面更简单,更严谨的方式,每个节点的key值不再需要去构造:
[url=] copycode.gif [/url]
e=session.findById("wnd[0]/shellcont/shell/shellcont[1]/shell[1]")node_total=len(e.GetAllNodeKeys()) # 得到所有的节点的总数for key in e.GetAllNodeKeys():    node_name=e.getItemText(key, "&Hierarchy")    if node_name == "损益表":        col1_value=e.getItemText(key, "C          1")        col2_value=e.getItemText(key, "C          3")        col3_value=e.getItemText(key, "C          5")     elif "存货变动" in node_name:        cmp_value=e.getItemText(key, "C          5")      if col1_value!="" and col2_value!="" and col3_value!="":        break  [url=] copycode.gif [/url]

  这段代码完美运行,上面的col1_value,col2_value,col3_value就对应上图中“tot.rpt.pr  tot.cmp.pr  绝对差异”  三个字段的值。从上面的代码可以看出来,我们手工想要看到某个根节点的值,需要对节点逐级展开(expand node),操作非常繁琐,通过python对过程自动化,后台的代码不需要展开节点本身,只要拿到节点的key 和name,我们原则上就可以取到每个节点的Itemtext,非常高效
您需要登录后才可以回帖 登录 | 注册

本版积分规则

QQ|克米亚sap论坛,sap账号,sap系统,sap ides,sap学习机,sap练习环境 ( 重庆瑞瑞宝科技有限公司 渝ICP备18002525号-10 )

GMT+8, 2021-8-2 07:54

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表