打赏

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 Files\Python39\Scripts;C:\Program Files\Python39\Lib\site-packages\pywin32_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 > width:
                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)

  

posted @ 2021-01-20 08:34  DanielXiaoyc  阅读(216)  评论(0编辑  收藏  举报