在带有 Python 的 SAP GUI 中使用多重处理时不可选取对象

问题描述 投票:0回答:2

那里。

我每天在 SAP GUI 中使用 Python 进行两次提取,这会消耗大量时间,因此必须更快地完成。因此,我正在尝试并行运行两个事务来解决这个问题。

我陷入了这里发生的同样问题使用Python在SAP GUI中进行多重处理,但我找不到解决这个问题的方法。基本上,当我尝试使用 Python 多处理库访问 SAP GUI 时,这是一个问题,并且内部模块之一尝试腌制 SAP GUI 会话对象。

这是错误:TypeError:无法腌制“PyIDispatch”对象

我正在尝试访问 SAP GUI 版本 740 以同时提取两个交易报告,就像我的朋友一样

上面我无法使用 RFC 工具。我知道这是不可维护的解决方案,但这将是这个问题的临时解决方案。

我的代码中有两个文件 - sap_novo:

import time, win32com.client
from subprocess import Popen
class SAP:
def __init__(self, site): # Função que inicia a classe SAP
     self.path = 'C:\\Program Files (x86)\\SAP\\FrontEnd\\SAPgui\\saplgpad.exe'
     self.site = site
     self.SSO = SSO
     self.con = None
     self.appl = None
     self.sap_gui = None
     self.session = None

    @property
    def session(self):
        return self._session
    
    @session.setter
    def session(self, value):
        self._session = value
    
    def connectToSAP(self): 
        Popen(self.path)
        time.sleep(15)
        SapGui = win32com.client.GetObject("SAPGUI")
        Appl = SapGui.GetScriptingEngine
        con = Appl.OpenConnection(self.site, True)
        self.session = con.Children(0)
        self.con = Appl.Connections(0)

主要

from multiprocess import Process
import sap_novo
import dill

def CX34(con_base, id_session):

    sap_session = con_base.Sessions(id_session)
    
    sap_session.findById("wnd[0]").maximize()
    sap_session.findById("wnd[0]/tbar[0]/okcd").text = "cx34"
    sap_session.findById("wnd[0]").sendVKey(0)

def FS10N(con_base, id_session):

    sap_session = con_base.Sessions(id_session)
    
    sap_session.findById("wnd[0]").maximize()
    sap_session.findById("wnd[0]/tbar[0]/okcd").text = "FS10N"
    sap_session.findById("wnd[0]").sendVKey(0)

def run_parallel(connection):
    p1 = Process(target=CX34, args=(connection, 0))
    p2 = Process(target=FS10N, args=(connection, 1))
    p1.start()
    p2.start()
    p1.join()
    p2.join()

def main():

    sap_obj = sap_novo.SAP('Environment')
    sap_obj.connectToSAP()
    sap_obj.checkLogin(sap_obj.session,"wnd[1]")
    run_parallel(sap_obj.con)

if __name__ == '__main__':
    main()

我使用 dill 包来了解使用它会发生什么

dill.detect.trace(True)
dill.pickles(sap_obj.session)
print(dill.dumps(sap_obj.session))

,我得到:

T4: \<class 'win32com.client.CDispatch'\>
 # T4 \[32 B\]
┬ D2: \<dict object at 0x20ba608a500\>
┬ T4: \<class 'win32com.client.CDispatch'\>
└ # T4 \[32 B\]
┬ D2: \<dict object at 0x20ba608a500\>

然后,它看起来像是 win32com.client.CDispatch 对象中序列化/pickle 的问题。

有人可以帮我吗?

谢谢!!

python pickle pywin32 sap-gui dill
2个回答
1
投票

伙计们。

我使用 python 线程包实现了我的目标。我无法使用多进程使其工作。

基本上,我正在创建两个线程,每个事务代码一个,并为每个函数传递一个会话 ID。

但是,要使这项工作有效,需要一个中间步骤。我必须使用 pythoncom 库在线程之间传递会话对象,因为在 python 中同时使用 COM 对象和线程存在一些限制。本主题帮助我做到这一点使用 win32com 进行多线程处理

从这个意义上说,我必须创建两个函数来序列化和反序列化会话对象。

    def serializeSessions(sap_sessions):
    sessions = []
    for session in sap_sessions:
        sessions.append(pythoncom.CoMarshalInterThreadInterfaceInStream(pythoncom.IID_IDispatch,
                                                                        session))
    return sessions

def deserializeSession(session_id):
    pythoncom.CoInitialize()
    #
    # Get instance from the id
    session = win32com.client.Dispatch(
        pythoncom.CoGetInterfaceAndReleaseStream(session_id, pythoncom.IID_IDispatch)
    )

    return session

这样,我在实例化线程之前进行序列化,然后传递序列化的会话对象并在事务函数内运行反序列化。


0
投票

非常感谢您的分享,我完全按照您所说的进行了测试,第一次就成功了,现在有了这个概念,我将能够加快我的 RPA 速度。

from sap import SAPConnector
import threading
import pythoncom
import win32com.client

SAP = SAPConnector()
sap_sessions = SAP.session(total_sessions=6)

def serializeSessions(sap_sessions):
    serial_sessions = []
    for session in sap_sessions:
        serial_sessions.append(
            pythoncom.CoMarshalInterThreadInterfaceInStream(pythoncom.IID_IDispatch,session)
            )
    return serial_sessions

def deserializeSession(serial_session):
    pythoncom.CoInitialize()
    session = win32com.client.Dispatch(
        pythoncom.CoGetInterfaceAndReleaseStream(serial_session, pythoncom.IID_IDispatch)
    )
    return session

def xk03(serial_session):
    session = deserializeSession(serial_session)
    session.findById("wnd[0]/tbar[0]/okcd").text = "/nxk03"
    session.findById("wnd[0]").sendVKey(0)

def me21n(serial_session):
    session = deserializeSession(serial_session)
    session.findById("wnd[0]/tbar[0]/okcd").text = "/nme21n"
    session.findById("wnd[0]").sendVKey(0)

def me33k(serial_session):
    session = deserializeSession(serial_session)
    session.findById("wnd[0]/tbar[0]/okcd").text = "/nme33k"
    session.findById("wnd[0]").sendVKey(0)

def xk03(serial_session):
    session = deserializeSession(serial_session)
    session.findById("wnd[0]/tbar[0]/okcd").text = "/nxk03"
    session.findById("wnd[0]").sendVKey(0)

def ie03(serial_session):
    session = deserializeSession(serial_session)
    session.findById("wnd[0]/tbar[0]/okcd").text = "/nie03"
    session.findById("wnd[0]").sendVKey(0)

def ml81n(serial_session):
    session = deserializeSession(serial_session)
    session.findById("wnd[0]/tbar[0]/okcd").text = "/nml81n"
    session.findById("wnd[0]").sendVKey(0)

def run_parallel(list_sessions):
    t1 = threading.Thread(target=xk03, args=(list_sessions[0], ))
    t2 = threading.Thread(target=me21n, args=(list_sessions[1], ))
    t3 = threading.Thread(target=me33k, args=(list_sessions[2], ))
    t4 = threading.Thread(target=xk03, args=(list_sessions[3], ))
    t5 = threading.Thread(target=ie03, args=(list_sessions[4], ))
    t6 = threading.Thread(target=ml81n, args=(list_sessions[5], ))
    t1.start()
    t2.start()
    t3.start()
    t4.start()
    t5.start()
    t6.start()
    t1.join()
    t2.join()
    t3.join()
    t4.join()
    t5.join()
    t6.join()

list_serial_sessions = serializeSessions(sap_sessions)
run_parallel(list_serial_sessions)
© www.soinside.com 2019 - 2024. All rights reserved.