You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多
文档控制台
免费开始使用

如何编写Windows Service定时运行Python脚本?含定点/周期执行需求

编写Windows Service定时运行Python脚本的实用方案

刚好我之前折腾过类似的需求,给你整理两种靠谱的实现路径,分别适合新手和需要灵活控制的场景,顺便把定时逻辑的实现也讲清楚:

一、快速上手:用NSSM把脚本封装成服务(新手推荐)

如果你不想写太多服务相关的代码,NSSM绝对是首选——它能把任意可执行程序直接包装成Windows服务,步骤超简单:

  • 先下载NSSM,解压到一个固定路径(比如C:\nssm),然后把这个路径加到系统环境变量PATH里,这样命令行就能直接调用它了。
  • 先确保你的Python脚本能正常运行,比如打开命令行跑一遍python C:\scripts\daily_task.py,没问题再往下走。
  • 打开管理员权限的命令提示符,输入nssm install PythonTaskService,会弹出一个图形配置界面:
    • Path:选你的Python解释器绝对路径,比如C:\Python39\python.exe
    • Arguments:填你要运行的脚本绝对路径,比如C:\scripts\daily_task.py
    • Working Directory:填脚本所在的文件夹路径,比如C:\scripts
    • 切到Details标签,给服务起个好记的名字和描述,方便以后在服务管理器里找
    • 切到Log On标签,设置服务运行的账户——如果脚本需要读写特定文件或者访问网络,建议用有对应权限的账户(比如管理员账户)
  • 配置完点OK,服务就安装好了。去服务管理器里找到这个服务,把启动类型改成自动,然后启动它就行。

不过要注意,NSSM只是帮你把脚本做成常驻服务,定时执行的逻辑还得在脚本里自己写,或者你也可以直接用Windows任务计划来触发脚本(后面会讲这个更省心的方式)。

二、灵活定制:用pywin32写自定义服务

如果需要更精细的控制(比如随时调整定时规则、记录服务运行日志),可以用pywin32库自己写服务代码,内置定时逻辑:

  • 先装pywin32:打开命令行跑pip install pywin32
  • 写服务代码,比如存成python_service.py,代码我给你写好了,你可以直接改参数:
import win32serviceutil
import win32service
import win32event
import servicemanager
import socket
import time
import subprocess
from datetime import datetime, timedelta

class PythonTaskService(win32serviceutil.ServiceFramework):
    # 服务的基本信息,自己改
    _svc_name_ = "PythonTaskService"
    _svc_display_name_ = "Python定时任务服务"
    _svc_description_ = "每天10点或每2小时执行指定Python脚本"

    def __init__(self, args):
        win32serviceutil.ServiceFramework.__init__(self, args)
        self.hWaitStop = win32event.CreateEvent(None, 0, 0, None)
        socket.setdefaulttimeout(60)
        self.is_running = True
        # 这里配置定时规则,二选一就行
        self.schedule_type = "daily"  # 可选 "daily"(每天固定时间)或 "interval"(间隔执行)
        self.daily_time = "10:00"     # 每天执行的时间点
        self.interval_hours = 2       # 间隔执行的小时数
        self.next_run_time = self.calculate_next_run()

    def calculate_next_run(self):
        now = datetime.now()
        if self.schedule_type == "daily":
            # 计算当天的目标时间,如果已经过了就推到明天
            target_time = datetime.strptime(self.daily_time, "%H:%M").replace(year=now.year, month=now.month, day=now.day)
            if target_time < now:
                target_time += timedelta(days=1)
            return target_time
        elif self.schedule_type == "interval":
            # 计算下一次执行时间,从现在往后推指定小时数
            return now + timedelta(hours=self.interval_hours)
        return now

    def SvcStop(self):
        # 处理服务停止的逻辑
        self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING)
        win32event.SetEvent(self.hWaitStop)
        self.is_running = False

    def SvcDoRun(self):
        # 服务启动时执行的逻辑
        servicemanager.LogMsg(servicemanager.EVENTLOG_INFORMATION_TYPE,
                              servicemanager.PYS_SERVICE_STARTED,
                              (self._svc_name_, ''))
        self.main()

    def main(self):
        # 服务的主循环,负责定时触发脚本
        while self.is_running:
            now = datetime.now()
            if now >= self.next_run_time:
                try:
                    # 执行你的Python脚本,记得改路径
                    subprocess.run(["python", "C:\\scripts\\daily_task.py"], check=True)
                    # 记录成功日志,在事件查看器里能看到
                    servicemanager.LogMsg(servicemanager.EVENTLOG_INFORMATION_TYPE,
                                          0,
                                          (f"脚本执行成功,时间:{now.strftime('%Y-%m-%d %H:%M:%S')}", ''))
                except subprocess.CalledProcessError as e:
                    # 记录失败日志
                    servicemanager.LogMsg(servicemanager.EVENTLOG_ERROR_TYPE,
                                          0,
                                          (f"脚本执行失败,错误:{str(e)}", ''))
                # 计算下一次执行时间
                self.next_run_time = self.calculate_next_run()
            # 每分钟检查一次,别占太多系统资源
            time.sleep(60)

if __name__ == '__main__':
    # 处理服务的安装、启动、停止等命令
    win32serviceutil.HandleCommandLine(PythonTaskService)
  • 安装服务:打开管理员命令提示符,跑python python_service.py install
  • 启动服务:要么跑python python_service.py start,要么去服务管理器里找到“Python定时任务服务”启动
  • 要是改了代码,先停服务python python_service.py stop,再更新服务python python_service.py update就行

三、更省心的定时方案:配合Windows任务计划

其实如果只是需要定时执行脚本,不一定非要写服务——Windows自带的任务计划程序足够好用,而且不用维护常驻服务:

  1. 打开任务计划程序,点“创建基本任务”
  2. 跟着向导走:先起个名字,然后设置触发器(选“每天”就设10点,选“按间隔”就设2小时)
  3. 设置操作:选“启动程序”,程序或脚本填Python解释器的绝对路径,参数填脚本的绝对路径
  4. 最后勾选“以最高权限运行”(如果脚本需要权限),完成就行

任务计划会自动在指定时间触发脚本,还能设置失败重试、邮件通知,比自己写定时逻辑靠谱多了。

四、踩过的坑要注意

  • 权限问题:不管是服务还是任务计划,运行的账户必须有脚本执行的权限——比如读写文件、访问网络,不然脚本会悄悄失败。
  • 环境一致性:一定要用Python解释器的绝对路径,别直接写python,不然服务/任务计划可能找不到你用的Python环境,导致模块找不到。
  • 日志记录:建议在脚本里加日志功能,或者用服务的日志(上面的代码里用了servicemanager,日志在事件查看器的“Windows日志->应用程序”里找),出问题了好排查。

内容的提问来源于stack exchange,提问作者skysoft999

火山引擎 最新活动