HOOOS

Python玩转Windows服务:定时任务So Easy!

0 34 代码诗人小李 PythonWindows服务定时任务
Apple

Python玩转Windows服务:定时任务So Easy!

想让你的Python脚本在后台默默运行,执行各种定时任务吗?把它变成一个Windows服务就搞定了!今天我就带你用Python的pywin32库,轻松创建一个Windows服务,让你的脚本像闹钟一样准时工作。

1. 准备工作:安装pywin32

首先,确保你已经安装了pywin32。没有的话,打开你的命令行窗口,输入:

pip install pywin32

安装完成后,运行以下命令来安装pywin32的服务支持:

python Scripts\pywin32_postinstall.py -install

(注意替换Scripts为你Python安装目录下的Scripts文件夹)

2. 编写服务脚本

接下来,我们需要编写一个Python脚本,它将作为Windows服务运行。这个脚本需要包含以下几个关键部分:

  • 服务类定义: 定义一个继承自win32serviceutil.ServiceFramework的类,这是所有Windows服务的基础。
  • SvcDoRun方法: 这是服务启动后执行的主要逻辑。在这里编写你的定时任务代码。
  • SvcStop方法: 这是服务停止时执行的清理工作。

下面是一个简单的例子,它每隔60秒向日志文件写入一条消息:

import win32serviceutil
import win32service
import win32event
import servicemanager
import time
import datetime

class MyService(win32serviceutil.ServiceFramework):
    _svc_name_ = 'MyPythonService'
    _svc_display_name_ = 'My Python Service'
    _svc_description_ = 'A Python service that writes a timestamp to a log file every minute.'

    def __init__(self, args):
        win32serviceutil.ServiceFramework.__init__(self, args)
        self.hWaitStop = win32event.CreateEvent(None, 0, 0, None)
        self.logger = self._getLogger()
        self.is_running = True

    def _getLogger(self):
        import logging
        import os
        import inspect

        logger = logging.getLogger(__name__)
        # Get the directory of the current script
        script_dir = os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe())))
        log_file_path = os.path.join(script_dir, 'service.log') # Log file in the same directory as the script
        hdlr = logging.FileHandler(log_file_path)
        formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')
        hdlr.setFormatter(formatter)
        logger.addHandler(hdlr)
        logger.setLevel(logging.INFO)
        return logger

    def SvcDoRun(self):
        self.logger.info("Service is starting...")
        while self.is_running:
            self.logger.info("Service is running... Current time: %s" % datetime.datetime.now())
            time.sleep(60)  # Wait for 60 seconds
            # Check if service is stopped
            if win32event.WaitForSingleObject(self.hWaitStop, 0) == win32event.WAIT_OBJECT_0:
                break
        self.logger.info("Service is stopping...")

    def SvcStop(self):
        self.logger.info("Service is stopping...")
        self.StopService()

    def StopService(self):
        self.is_running = False
        self.logger.info("Service is stopped.")
        self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING)
        win32event.SetEvent(self.hWaitStop)
        self.ReportServiceStatus(win32service.SERVICE_STOPPED)

if __name__ == '__main__':
    win32serviceutil.HandleCommandLine(MyService)

代码解释:

  • _svc_name_:服务的名称,在Windows服务管理器中显示。
  • _svc_display_name_:服务的显示名称,更友好的名称。
  • _svc_description_:服务的描述,解释服务的作用。
  • SvcDoRun:服务启动后,这个方法会被循环调用。在这里可以编写你的定时任务逻辑。示例中,我们每隔60秒向service.log文件写入一条时间戳。
  • SvcStop:服务停止时,这个方法会被调用。在这里可以进行一些清理工作,例如关闭文件、释放资源等。

3. 安装、启动和停止服务

将上面的代码保存为my_service.py(或者其他你喜欢的名字)。然后,使用以下命令来安装、启动和停止服务:

  • 安装服务:

    python my_service.py install
    
  • 启动服务:

    python my_service.py start
    
  • 停止服务:

    python my_service.py stop
    
  • 移除服务:

    python my_service.py remove
    

你也可以在Windows服务管理器(在搜索栏输入“服务”)中找到你的服务,并进行启动、停止等操作。

4. 常见问题及解决方案

  • 服务安装失败: 确保你以管理员身份运行命令行窗口。
  • 服务启动失败: 检查你的脚本是否有语法错误,以及依赖的库是否都已安装。查看service.log文件,看看是否有错误信息。
  • 服务无法停止: 可能是因为SvcStop方法中没有正确处理停止事件。确保在SvcStop方法中设置了self.is_running = False,并且调用了win32event.SetEvent(self.hWaitStop)

5. 进阶技巧

  • 使用第三方库进行定时任务: schedule是一个流行的Python库,可以让你更灵活地定义定时任务。你可以将schedule库集成到你的服务脚本中。
  • 使用配置文件: 将服务的配置信息(例如日志文件路径、定时任务间隔等)放在配置文件中,方便修改和管理。
  • 异常处理:SvcDoRun方法中添加异常处理,防止服务因为脚本错误而崩溃。

总结

通过pywin32库,我们可以轻松地将Python脚本变成Windows服务,实现各种定时任务。希望这篇文章能帮助你入门Windows服务开发。快去尝试一下,让你的Python脚本在后台默默发光发热吧!

参考资料:

点评评价

captcha
健康