赞
踩
通常在windows平台上开发完python服务后,需要通过引用虚拟环境后再运行,或者使用IDE软件启动,但如果想做成开机启动的本地服务,每次都这样启动就太麻烦了。
该文档介绍这个方法是把python程序制作成一个windows,启停特别方便,而且还可以设置开机启动。虚拟环境依赖的库也不需要考虑,只要在构建的时候在虚拟环境下构建,就会自动将依赖的库打包进去。
-
- # -*- coding:utf-8 -*-
- import win32serviceutil
- import win32service
- import win32event
- import sys
- import os
-
- #设置编码
- reload(sys)
- sys.setdefaultencoding('utf-8')
-
- #windows服务中显示的名字
- class zlsService(win32serviceutil.ServiceFramework):
- _svc_name_ = 'web_movie' ###可以根据自己喜好修改
- _svc_display_name_ = 'web_movie' ###可以根据自己喜好修改
- _svc_description_ = 'web_movie' ###可以根据自己喜好修改
-
- def __init__(self,args):
- win32serviceutil.ServiceFramework.__init__(self,args)
- self.stop_event = win32event.CreateEvent(None, 0, 0, None)
- self.run = True
-
- def SvcDoRun(self):
- # 这里是你的启动代码,由于我的是flask框架程序,只需要把我的主文件from过来即可。
- from web_movie import app
- app.run()
-
- def SvcStop(self):
- self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING)
- win32event.SetEvent(self.stop_event)
- self.ReportServiceStatus(win32service.SERVICE_STOPPED)
- self.run = False
-
- if __name__ == '__main__':
- import sys
- import servicemanager
- if len(sys.argv) == 1:
- try:
- evtsrc_dll = os.path.abspath(servicemanager.__file__)
- servicemanager.PrepareToHostSingle(zlsService) #如果修改过名字,名字要统一
- servicemanager.Initialize('zlsService',evtsrc_dll) #如果修改过名字,名字要统一
- servicemanager.StartServiceCtrlDispatcher()
- except win32service.error as details:
- import winerror
- if details == winerror.ERROR_FAILED_SERVICE_CONTROLLER_CONNECT:
- win32serviceutil.usage()
- else:
- win32serviceutil.HandleCommandLine(zlsService) #如果修改过名字,名字要统一

pip install PyInstaller==3.4
pip install pywin32==224
- :: 停止运行的服务
- sc stop web_movie
- :: 删除这个服务
- sc delete web_movie
- :: 等个几秒钟,服务刚停止,文件不会马上释放,不然文件不让删除
- TIMEOUT /T 3
- :: 删除旧版本构建的内容
- rmdir /s/q dist
- rmdir /s/q build
- del PythonService.spec
- :: 构建现在的程序,这里有个坑,由于templates目录和static目录和代码不是直接引用,在pyinstaller构建的时候会忽略,导致服务无法运行,后面详细介绍。
- pyinstaller -F --add-data "templates;templates" --add-data "static;static" PythonService.py
- :: 将构建好的exe程序安装到系统服务
- dist\PythonService.exe install
- :: 启动服务
- sc start web_movie


如果启动后立即停止,或者弹窗说“服务没有及时响应启动或控制请求”,这时候可以查看windows的计算机管理界面应用日志,来看详细信息。

- Traceback (most recent call last):
- File "site-packages\win32\lib\win32serviceutil.py", line 839, in SvcRun
- File "PythonService.py", line 28, in SvcDoRun
- File "site-packages\flask\app.py", line 943, in run
- File "site-packages\werkzeug\serving.py", line 812, in run_simple
- File "site-packages\werkzeug\_reloader.py", line 267, in run_with_reloader
- ValueError: signal only works in main thread
上面这个报错使我的代码出现过得,经过我的各种最小化测试,发现这个错误是加载配置项的时候就会出现,最终定位到了我的一行配置文件。
DEBUG = True,这一行配置让我排查了整整一天。
修复了上面的问题,我的的服务终于起来了,但是又发现,在浏览器里面竟然无法访问。如下提示:
- Internal Server Error
- The server encountered an internal error and was unable to complete your request. Either the server is overloaded or there is an error in the application.
- 这个问题也让我苦恼了很久,在我最小化测试的时候,缩减到仅剩一个hello world都无法正常显示,但是创建一个新的flask项目就可以正常显示,经过我细心的diff这两个项目,发现我在return的时候使用了render_template模板,然而这个目录在pyinstaller的时候,并没有打包进来,然后这一切都明白了,就是因为在构建的时候没有将这个目录添加进来,导致项目启动后无法使用模板文件。
-
- 修复方法就是bat文件内写的,添加上静态目录的编译就可以了。
- pyinstaller -F --add-data "templates;templates" --add-data "static;static" PythonService.py
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。