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)