• Python-Serivce的开发和遇到的坑


    这几天我用Python做了一个PDF转JPG的工具,转的速度极快,比较推荐使用。

    做好工具后,想做成服务,于是我就在网上开始找资料,最后我自己成功开发并发布一个Python的Windows Service。

    先来个小型的服务,基本没有什么功能的,只具备写几行日志的功能。

    _svc开头的是系统的约定,是不能修改的。

    Svc开头的方法也是系统的约定,也是不能修改的。

    #-*- coding:utf-8 -*-
    
    import win32serviceutil
    import win32service
    import win32event
    
    class PythonService(win32serviceutil.ServiceFramework):
        _svc_name_="PythonService"
        _svc_display_name_="Python Service Demo"
        _svc_description="Python service demo"
    
        def __init__(self,args):
            win32serviceutil.ServiceFramework.__init__(self,args)
            self.hWaitStop =win32event.CreateEvent(None,0,0,None)
            self.logger=self._getLogger()
            self.isAlive=True
        
        def _getLogger(self):
            import logging
            import os
            import inspect
    
            logger=logging.getLogger('[PythonService]')
            this_file =inspect.getfile(inspect.currentframe())
            dirpath=os.path.abspath(os.path.dirname(this_file))
            handler=logging.FileHandler(os.path.join(dirpath,"service.log"))
    
            formatter = logging.Formatter(
                '%(asctime)s %(name)-12s %(levelname)-8s %(message)s')
            handler.setFormatter(formatter)
            logger.addHandler(handler)
            logger.setLevel(logging.INFO)
    
            return logger
        
        def SvcDoRun(self):
            import time
            self.logger.error("svc do run...")
            while self.isAlive:
                self.logger.error("I am alive.")
                time.sleep(1)
    
        def SvcStop(self):
            self.logger.error("svc do stop...")
            self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING)
    
            win32event.SetEvent(self.hWaitStop)
            self.isAlive=False
    
    
    if __name__=='__main__':
        win32serviceutil.HandleCommandLine(PythonService)
        
    

    开发服务记得要安装pywin32,用pip install pywin32 进行安装

    写好代码后,有两种安装方法:

    第一种基于源码的:python 源码完整路径名称.py 命令

    命令解释: install 安装。强调下,一定要在管理员的方式下CMD进行。

             start 启动,如果启动不起来,把C:Program FilesPython39Scripts;C:Program FilesPython39Libsite-packagespywin32_system32;这个路径配置到系统的Path中,并且不要使用默认的本地系统账号,用一个有管理员权限的账号。

             stop 停止,如果停止不了,在任务管理器中找到PythonService,然后强行结束

             update 更新,在源码有修改的时候要先update

    第二种基于部署包的:

       先安装pyinstaller,用pip install pyinstaller

     然后用 pyinstall -F -c 源码完整路径.py ,系统会在当前目录下生成一个子目录dist和同名的exe文件

    安装:

    exe文件 命令

    命令解释同上。

    完整的一个服务的源码如下:

    #-*- coding:utf-8 -*-
    #要安装pywin32
    
    import win32serviceutil
    import win32service
    import win32event
    import win32timezone
    
    from pdf2image import convert_from_path
    from pathlib import Path
    
    from os import listdir
    from PIL import Image
    
    import os
    import time
    from shutil import copyfile
    import shutil
    
    
    class PythonService(win32serviceutil.ServiceFramework):
        _svc_name_ = "PythonService PDF2JPG"
        _svc_display_name_ = "Python Service PDF2JPG"
        _svc_description = "Python service PDF2JPG"
    
        def __init__(self, args):
            win32serviceutil.ServiceFramework.__init__(self, args)
            self.hWaitStop = win32event.CreateEvent(None, 0, 0, None)
            self.logger = self._getLogger()
            self.isAlive = True
            self.path_to_watch = "D:\PDFS"
    
        def _getLogger(self):
            import logging
            import os
            import inspect
    
            logger = logging.getLogger('[PythonService_PDF2JPG]')
            this_file = inspect.getfile(inspect.currentframe())
            dirpath = os.path.abspath(os.path.dirname(this_file))
            handler = logging.FileHandler(os.path.join(
                dirpath, "pythonservice_pdf2jpg.log"))
    
            formatter = logging.Formatter(
                '%(asctime)s %(name)-12s %(levelname)-8s %(message)s')
            handler.setFormatter(formatter)
            logger.addHandler(handler)
            logger.setLevel(logging.INFO)
    
            return logger
    
        def pdf_to_image(self, pdf_filename):
            #判断路径是否存在
    
            #if not pdf_filename.upper().endswith(".PDF"):
            #    return
            #print('处理 pdf_filename:', pdf_filename)
            self.logger.info("Process File:"+pdf_filename)
            filename_withoutext = pdf_filename.split('.')[0]
            out_path = Path(filename_withoutext)
            #print('out_path', out_path)
            out_path_full = os.path.join(self.path_to_watch, out_path)
            out_path_full_trim = out_path_full.strip()
            #print('完整路径:', out_path_full)
            self.logger.info("out_path_full:"+out_path_full_trim)
            out_path_full_check = Path(out_path_full_trim)
            if out_path_full_check.exists():
                self.logger.info("path exist")
                #shutil.rmtree(out_path_full)
                #self.logger.info("path delete")
            if not out_path_full_check.exists():
                #print('创建目录:', out_path_full)
                self.logger.info("not exist,to create")
                os.mkdir(out_path_full_trim)
            #print('开始转换')
            pdf_filename = os.path.join(self.path_to_watch, pdf_filename)
            self.logger.info("pdf_filename:"+pdf_filename)
            #print('filename:', pdf_filename)
    
            pages = convert_from_path(pdf_filename, dpi=400, output_folder=None, fmt="JPEG",
                                      thread_count=1)
            self.logger.info("pages count:"+str(len(pages)))
    
            pindex = 1
            for p in pages:
                p_f = os.path.join(out_path_full_trim, str(pindex)+'.jpg')
                p.save(p_f)
                pindex = pindex+1
    
            time.sleep(1)
            #print('转换完成')
            self.logger.info("convert end")
            self.contact_image(out_path_full)
            #print('合并完成')
            path_file = pdf_filename.split('.')[0]
            sub_path = os.path.join(self.path_to_watch, path_file).strip()
            #print('删除目录', sub_path)
            shutil.rmtree(sub_path)
            self.logger.info("delete path:"+sub_path)
    
        def open_image(self, out_path_full, fn):
            image_file = os.path.join(out_path_full, fn)
            #print('打开图片路径', image_file)
            return Image.open(image_file)
    
        def contact_image(self, out_path_full):
            #print('开始合并')
            #print('合并路径:', out_path_full)
            out_path_full_trim = out_path_full.strip()
            image_list = [self.open_image(out_path_full_trim, fn)
                          for fn in listdir(out_path_full_trim) if fn.endswith('.jpg')]
            #print('图片数量:', len(image_list))
            images = []
            width = 0
            height = 0
            total_height = 0
            max_width = 0
    
            for i in image_list:
                if i.size[0] > width or i.size[1] > height:
                    width, height = i.size
    
                #print('width %d,height %d ' % (width, height))
                if height > 
                    new_image = i.resize((1102, 1564), Image.BILINEAR)  # 551*782
                    images.append(new_image)
                    total_height = total_height+1564
                    max_width = 1102
                else:
                    new_image = i.resize((1102, 776), Image.BILINEAR)  # 551*782
                    images.append(new_image)
                    total_height = total_height+776
                    max_width = 1102
    
                result = Image.new(
                    images[0].mode, (max_width, total_height), "white")
            #print('total_height:', total_height)
            save_path = out_path_full+".jpg"
            #copy_to=out_path_full+".swf"
    
            #print('save path:', save_path)
            height_total = 0
            for i, im in enumerate(images):
                height_im = im.size[1]
                #print('height_im %d' % height_im)
                result.paste(im, box=(0, height_total))
                result.save(save_path)
                height_total = height_total+height_im
    
            #copyfile(save_path,copy_to)
    
        def service(self):
            pdf_files = dict([(f, None) for f in os.listdir(
                self.path_to_watch) if f.upper().endswith('.PDF')])
            for f in pdf_files:
                f_full = os.path.join(self.path_to_watch, f)
                f_jpg = f.split('.')[0]+'.jpg'
                f_jpg_full = os.path.join(self.path_to_watch, f_jpg)
    
                #self.logger.info(msg="PDF File:"+f_full)
                #self.logger.info(msg="JPG File:"+f_jpg_full)
                #print(f_jpg_full)
                f_jpg_full_check = Path(f_jpg_full)
                if not f_jpg_full_check.exists():
                    self.logger.info(msg="Not found JPG File:"+f_jpg_full)
                    #print(f_full)
                    #time.sleep(1)
                    #self.logger.info(msg="Add File:"+f_full)
                    #print('文件名:', f_full)
                    self.pdf_to_image(f)
                    self.logger.info(msg="[OK]Add File:"+f_full)
    
        def SvcDoRun(self):
            import time
            self.logger.info("Service Start...")
            self.logger.info("Monitor Path:"+self.path_to_watch)
            while self.isAlive:
                try:
                    self.logger.info(msg="Doing...")
                    self.service()
                    time.sleep(3)
                except Exception as e:
                    self.logger.error("Error Info:"+e)
                    time.sleep(10)
    
        def SvcStop(self):
            self.logger.info("Service Stop...")
            self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING)
    
            win32event.SetEvent(self.hWaitStop)
            self.isAlive = False
    
    
    if __name__ == '__main__':
        win32serviceutil.HandleCommandLine(PythonService)
    

      

  • 相关阅读:
    Your First ASP.NET 5 Application on a Mac
    vnextcn
    基于微服务的软件架构模式
    数组链表下标指针map list
    十一、从头到尾彻底解析Hash 表算法
    failed to create hive metastore database tables
    VSCode 常用插件
    HTML中块级行级元素小分类
    WEB前端程序员需要的网站整理
    UI1_HTTP下载
  • 原文地址:https://www.cnblogs.com/xiaoyichong/p/14301049.html
Copyright © 2020-2023  润新知