由于SAP系统自身原因,或者公司内部ABAP代码的算法效率不高,我们经常遇到,手工执行某个事务代码下载某个报表会非常耗时,小爬曾见过公司某个自开发的报表,单家公司的数据下载超过半小时。如果我们刚好接到一个自动化需求:批量下载N个公司的某些报表数据,即使我们用python脚本实现了该场景的自动化,效率依然不高。
或许我们可以尝试python的多线程技术来加速。这应该是个好主意,现在小爬就带着大家往多线程这个方向思考。
SAP GUI的会话数量一般都有限制,各个公司的SAP策略或有不同,在小爬所在的公司,SAP GUI客户端允许的会话数不超过6,我们不妨用多个会话分别去下载数据。小爬遇到的场景是:有N家公司,分别进入4个事务代码下载四张不同的表,这四张表的导出速度各有不同,有的较快,有的极慢。
方案一:我们启用四个sap会话,分别下载这四张表,每次参数中传入不同的公司代码;
方案二:我们开启最大SAP会话数6,每个会话都执行一些公司代码,也都会下载到这四张表。
仔细思考后不难发现,方案二可以将下载速度最大化。方案一中各个会话对应的报表下载速度各不相同,最终速度受最慢的那个影响,而且它只能根据四张报表来启用四个会话线程;而方案一,则可以同时开启六个SAP会话线程,且每个会话下都会下载这四张表,无形中,避免了”一个会话在苦战,其它会话全围观“的尴尬局面。
具体到代码层面,我们需要批量创建多个sap会话,新建一个全局的任务队列companyQ,每个sap会话独自不停去队列中取任务(下载需要的参数),驱动各自负责的SAP会话来完成数据的下载,当队列中所有任务都完成了,意味着线程结束。等以上思路都琢磨明白了,代码该怎么写就不再是一个问题了。
第一步:定义连接sap的方法,并自动开启N个session会话
第二部:定义下载SAP数据的方法
第三步:开启多个线程,分别调用同一个方法,传入不同session的index作为参数,实现对多个会话的自动化控制
def connect_SAP(maxSessionNum): '''连接SAP,并创建maxSessionNum个session会话,返回session列表(含session索引)''' SapGuiAuto = win32com.client.GetObject("SAPGUI") application = SapGuiAuto.GetScriptingEngine connection = application.Children(0) indexSessions=[] session=connection.Children(0) cnt=connection.Children.Count if cnt<maxSessionNum: for _ in range(maxSessionNum-cnt): session.Createsession() sleep(0.5) sleep(2) for index,session in enumerate(connection.Children): indexSessions.append([index,session]) SapGuiAuto=None application=None connection=None session=None return indexSessions
def exportSapData(sessionIndex): '''给定公司代码,期间,依次导出应收社保、公积金,应付社保、公积金报表数据''' pythoncom.CoInitialize() SapGuiAuto = win32com.client.GetObject("SAPGUI") application = SapGuiAuto.GetScriptingEngine connection = application.Children(0) session=connection.Children(sessionIndex) '''输入zhr054,导出HR社保往来挂账应付公积金明细表''' session.findById("wnd[0]").iconify() unfinishedNum=companyQ.unfinished_tasks while True: lk.acquire() if not companyQ.empty(): companyCode=companyQ.get(block=False) else: lk.release() break lk.release() downloadFunc(companyCode,reportPeriod)
下面的代码便演示了如何借助python多线程技术,针对每个线程,传入的参数就是session的索引号(0-6),最终把他们分别启动起来~
connect_SAP(maxSessionNum=5) sleep(3) threads = [] for i in range(6): threads.append(threading.Thread(target=exportSapData,args=(i,))) for companyCode in companies: companyQ.put(companyCode) for t in threads: t.setDaemon(True) t.start() for t in threads: t.join() print ("all over %s" %ctime()) endtime = datetime.datetime.now() secs = (endtime - starttime).seconds minutes = secs // 60 second = secs % 60 timeStr = str(minutes) + '分钟' + str(second) + "秒" root=tk.Tk() root.withdraw() tkinter.messagebox.showinfo("信息",f"已完成所有数据下载,运行时间为:{timeStr}")
以上,就是小爬利用python多线程来驱动sap多个会话进行特定自动化操作的主要过程。基于这一波操作,整个下载效率可以提升4-6倍。那一刻,仿佛有6个自动化机器人在同时帮小爬分担枯燥的数据下载工作,幸福感瞬间拉满!!!
有任何疑问,欢迎评论区积极留言,同时也欢迎扫码关注我的公众号,获取更多爬虫、数据分析的知识!