我正在为一组共享存储在数据库中的各种相关对象的程序绘制体系结构草图。我希望其中一个程序充当服务,为这些对象上的操作提供更高级别的接口,而其他程序通过该服务访问对象。

我目前的目标是将Python和Django框架作为实现该服务的技术。我很确定我知道如何在Linux中守护Python程序。但是,系统应该支持Windows,这是一个可选的规格项。我几乎没有Windows编程经验,对Windows服务也没有任何经验。

是否有可能运行Python程序作为Windows服务(即自动运行,无需用户登录)?我不一定要实现这一部分,但我需要一个大致的想法,以便决定是否沿着这些路线进行设计。

编辑:谢谢你到目前为止所有的回答,他们是相当全面的。我还想知道一件事:Windows是如何感知我的服务的?我可以使用本机Windows实用程序管理它吗?在/etc/init.d中放置启动/停止脚本的等效内容是什么?


是的,你可以。我使用ActivePython附带的pythoncom库,或者可以使用pywin32 (Python for Windows扩展)安装。

这是一个简单服务的基本框架:

import win32serviceutil
import win32service
import win32event
import servicemanager
import socket


class AppServerSvc (win32serviceutil.ServiceFramework):
    _svc_name_ = "TestService"
    _svc_display_name_ = "Test Service"

    def __init__(self,args):
        win32serviceutil.ServiceFramework.__init__(self,args)
        self.hWaitStop = win32event.CreateEvent(None,0,0,None)
        socket.setdefaulttimeout(60)

    def SvcStop(self):
        self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING)
        win32event.SetEvent(self.hWaitStop)

    def SvcDoRun(self):
        servicemanager.LogMsg(servicemanager.EVENTLOG_INFORMATION_TYPE,
                              servicemanager.PYS_SERVICE_STARTED,
                              (self._svc_name_,''))
        self.main()

    def main(self):
        pass

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

您的代码将在main()方法中运行——通常带有某种无限循环,检查SvcStop方法中设置的标志可能会中断这种循环


实际上,可以将任何Windows可执行文件安装为服务。

方法一:使用rktools.exe中的instsrv和srvany

对于Windows Home Server或Windows Server 2003(也适用于WinXP), Windows Server 2003资源工具包工具附带了可以同时使用的实用程序,称为instsrv.exe和srvany.exe。有关如何使用这些util的详细信息,请参阅Microsoft KB文章KB137890。

对于Windows Home Server,这些实用程序有一个非常友好的包装,叫做“任何服务安装程序”。

方法二:使用ServiceInstaller for Windows NT

还有另一种替代方案,使用ServiceInstaller for Windows NT(可在这里下载),并提供python指令。与名字相反,它也适用于Windows 2000和Windows XP。下面是一些关于如何将python脚本作为服务安装的说明。

Installing a Python script Run ServiceInstaller to create a new service. (In this example, it is assumed that python is installed at c:\python25) Service Name : PythonTest Display Name : PythonTest Startup : Manual (or whatever you like) Dependencies : (Leave blank or fill to fit your needs) Executable : c:\python25\python.exe Arguments : c:\path_to_your_python_script\test.py Working Directory : c:\path_to_your_python_script After installing, open the Control Panel's Services applet, select and start the PythonTest service.

在我最初的回答之后,我注意到SO上已经贴出了与之密切相关的问答。参见:

我可以将Python脚本作为服务运行吗(在Windows中)?如何?

如何让Windows知道我用Python编写的服务?


虽然我在几周前对所选的答案进行了投票,但与此同时,我在这个话题上挣扎了很多。感觉使用特殊的Python安装并使用特殊的模块将脚本作为服务运行是一种错误的方式。可移植性如何?

我偶然发现了很棒的非吸吮服务管理器,它让处理Windows服务变得非常简单和理智。我想既然我可以将选项传递给已安装的服务,那么我也可以选择我的Python可执行文件并将脚本作为一个选项传递。

我还没有尝试过这个解决方案,但我会马上尝试,并在此过程中更新这篇文章。我也对在Windows上使用virtualenvs感兴趣,所以我可能迟早会想出一个教程,并链接到这里。


最简单的方法是使用本机命令sc.exe:

sc create PythonApp binPath= "C:\Python34\Python.exe --C:\tmp\pythonscript.py"

引用:

https://technet.microsoft.com/en-us/library/cc990289 (v = ws.11) . aspx 当用sc.exe创建服务时,如何传递上下文参数?


pysc: Python上的服务控制管理器

作为从pythonhosted.org获取的服务运行的示例脚本:

from xmlrpc.server import SimpleXMLRPCServer from pysc import event_stop class TestServer: def echo(self, msg): return msg if __name__ == '__main__': server = SimpleXMLRPCServer(('127.0.0.1', 9001)) @event_stop def stop(): server.server_close() server.register_instance(TestServer()) server.serve_forever() Create and start service import os import sys from xmlrpc.client import ServerProxy import pysc if __name__ == '__main__': service_name = 'test_xmlrpc_server' script_path = os.path.join( os.path.dirname(__file__), 'xmlrpc_server.py' ) pysc.create( service_name=service_name, cmd=[sys.executable, script_path] ) pysc.start(service_name) client = ServerProxy('http://127.0.0.1:9001') print(client.echo('test scm')) Stop and delete service import pysc service_name = 'test_xmlrpc_server' pysc.stop(service_name) pysc.delete(service_name)

pip install pysc

一步一步地解释如何使它工作:

1-首先根据上面提到的基本框架创建一个python文件。并将其保存到一个路径,例如:"c:\PythonFiles\AppServerSvc.py"

import win32serviceutil
import win32service
import win32event
import servicemanager
import socket


class AppServerSvc (win32serviceutil.ServiceFramework):
    _svc_name_ = "TestService"
    _svc_display_name_ = "Test Service"


    def __init__(self,args):
        win32serviceutil.ServiceFramework.__init__(self,args)
        self.hWaitStop = win32event.CreateEvent(None,0,0,None)
        socket.setdefaulttimeout(60)

    def SvcStop(self):
        self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING)
        win32event.SetEvent(self.hWaitStop)

    def SvcDoRun(self):
        servicemanager.LogMsg(servicemanager.EVENTLOG_INFORMATION_TYPE,
                          servicemanager.PYS_SERVICE_STARTED,
                          (self._svc_name_,''))
        self.main()

    def main(self):
        # Your business logic or call to any class should be here
        # this time it creates a text.txt and writes Test Service in a daily manner 
        f = open('C:\\test.txt', 'a')
        rc = None
        while rc != win32event.WAIT_OBJECT_0:
            f.write('Test Service  \n')
            f.flush()
            # block for 24*60*60 seconds and wait for a stop event
            # it is used for a one-day loop
            rc = win32event.WaitForSingleObject(self.hWaitStop, 24 * 60 * 60 * 1000)
        f.write('shut down \n')
        f.close()

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

在这一步,我们应该注册我们的服务。

以管理员身份运行命令提示符,输入as:

sc create TestService binpath= "C:\Python36\Python.exe C:\ PythonFiles\AppServerSvc.py" DisplayName= "TestService" start= auto

binpath的第一个参数是python.exe的路径

binpath的第二个参数是我们已经创建的python文件的路径

不要忘记在每个“=”号后面加一个空格。

如果一切正常,你应该能看到

[SC] CreateService SUCCESS . [SC

现在你的python服务已经被安装为windows服务了。你可以在服务管理器和注册表中看到它:

HKEY_LOCAL_MACHINE \ SYSTEM \ CurrentControlSet \ \ TestService服务

3-好了。您可以在服务管理器上启动服务。

您可以执行提供此服务框架的每个python文件。


最简单的方法是使用:NSSM -非吸吮服务管理器。只需下载并解压缩到您选择的位置。它是一个自包含的实用程序,大约300KB(比为此目的安装整个pywin32套件少得多),不需要“安装”。zip包含一个64位版本和一个32位版本的实用程序。两者都应该在当前系统上运行良好(您可以使用32位版本来管理64位系统上的服务)。

GUI的方法

1 -将python程序作为服务安装。以管理员身份打开Win提示符

c:\>nssm.exe install WinService

2 -在NSSM的GUI控制台:

路径:C: \ Python27 \ Python27.exe

启动目录:C:\Python27

参数:c: \ WinService.py

3 -在services.msc上检查已创建的服务

脚本方法(没有GUI)

如果您的服务应该是自动化的、非交互式过程的一部分,例如批处理或安装程序脚本,那么这是非常方便的。假设这些命令是使用管理权限执行的。

为了方便起见,这里将命令简单地称为nssm.exe。但是,建议在脚本中用完整路径c:\path\to\nssm.exe更显式地引用它,因为它是一个自包含的可执行文件,可能位于系统不知道的私有路径中。

1. 安装服务

您必须为服务指定一个名称,正确的Python可执行文件的路径,以及脚本的路径:

nssm.exe install ProjectService "c:\path\to\python.exe" "c:\path\to\project\app\main.py"

更明确:

nssm.exe install ProjectService 
nssm.exe set ProjectService Application "c:\path\to\python.exe"
nssm.exe set ProjectService AppParameters "c:\path\to\project\app\main.py"

或者,你可能希望你的Python应用程序作为一个Python模块启动。一个简单的方法是告诉nssm它需要更改到正确的起始目录,就像你自己从命令shell启动时所做的那样:

nssm.exe install ProjectService "c:\path\to\python.exe" "-m app.main"
nssm.exe set ProjectService AppDirectory "c:\path\to\project"

这种方法适用于虚拟环境和自包含(嵌入式)的Python安装。只需确保在这些环境中使用常规方法正确解决了任何路径问题。nssm有一种方法可以在需要时设置环境变量(例如PYTHONPATH),还可以启动批处理脚本。

2. 启动服务

nssm.exe start ProjectService 

3.停止服务

nssm.exe stop ProjectService

4. 若要删除服务,请指定confirm参数以跳过交互式确认。

nssm.exe remove ProjectService confirm

我开始使用pywin32作为服务托管。

一切都很好,但我遇到了一个问题,即服务无法在系统启动时的30秒内启动(Windows的默认超时)。这对我来说至关重要,因为Windows启动是在一台物理机上托管的多个虚拟机上同时进行的,IO负载非常大。 错误消息包括:

错误1053:服务没有及时响应启动或控制请求。

错误7009:等待<ServiceName>服务连接的超时(30000毫秒)。

我与pywin进行了大量的斗争,但最终使用了这个答案中提出的NSSM。移居到那里很容易。


使用win32serviceutil的公认答案是可行的,但它很复杂,使调试和更改更加困难。使用NSSM(非吸吮服务管理器)要容易得多。你编写并轻松调试一个普通的python程序,当它最终工作时,你使用NSSM在不到一分钟的时间内将其安装为服务:

在一个提升的(管理)命令提示符中,运行nssm.exe安装NameOfYourService并填写以下选项:

path:(python.exe的路径,例如C:\Python27\ python.exe) 参数:(python脚本的路径,例如c:\path\to\program.py)

顺便说一下,如果您的程序打印了想要保存在日志文件中的有用消息,那么NSSM也可以为您处理这个问题。


NSSM在python 3+

(我用pyinstaller将我的.py文件转换为.exe)

nssm: 如前所述

运行nssm install {ServiceName} 在NSSM的控制台: \ \你\ program.exe路径:路径 启动目录:路径\to\your\ #与路径相同,但没有你的program.exe 参数:空

如果您不想将项目转换为.exe

用python{{你的python.py文件名}}创建一个.bat文件 并将路径设置为。bat文件


使用循环或子线程的完整pywin32示例

在断断续续地研究了几天之后,这里是我希望找到的答案,使用pywin32来保持它的良好和自包含。

这是一个基于循环和一个基于线程的解决方案的完整工作代码。 它可以在python 2和3上运行,尽管我只在2.7和Win7上测试了最新版本。循环应该适用于轮询代码,而tread应该适用于更类似于服务器的代码。它似乎可以很好地与没有标准方法来优雅地关闭的女招待wsgi服务器一起工作。

我还想指出的是,似乎有大量的例子,像这个,几乎是有用的,但在现实中误导,因为他们盲目地剪切和粘贴其他的例子。我可能是错的。但如果你从不等待,为什么要创建一个事件呢?

尽管如此,我仍然觉得我在这里的立场有些动摇,特别是关于线程版本的退出有多干净,但至少我相信这里没有任何误导。

要运行,只需将代码复制到文件中并按照说明操作即可。

更新:

使用一个简单的标志来终止线程。重要的一点是“线程完成”打印。 有关从不合作的服务器线程退出的更详细的示例,请参阅我关于女服务生wsgi服务器的帖子。

# uncomment mainthread() or mainloop() call below
# run without parameters to see HandleCommandLine options
# install service with "install" and remove with "remove"
# run with "debug" to see print statements
# with "start" and "stop" watch for files to appear
# check Windows EventViever for log messages

import socket
import sys
import threading
import time
from random import randint
from os import path

import servicemanager
import win32event
import win32service
import win32serviceutil
# see http://timgolden.me.uk/pywin32-docs/contents.html for details


def dummytask_once(msg='once'):
    fn = path.join(path.dirname(__file__),
                '%s_%s.txt' % (msg, randint(1, 10000)))
    with open(fn, 'w') as fh:
        print(fn)
        fh.write('')


def dummytask_loop():
    global do_run
    while do_run:
        dummytask_once(msg='loop')
        time.sleep(3)


class MyThread(threading.Thread):
    def __init__(self):
        threading.Thread.__init__(self)

    def run(self):
        global do_run
        do_run = True
        print('thread start\n')
        dummytask_loop()
        print('thread done\n')

    def exit(self):
        global do_run
        do_run = False


class SMWinservice(win32serviceutil.ServiceFramework):
    _svc_name_ = 'PyWinSvc'
    _svc_display_name_ = 'Python Windows Service'
    _svc_description_ = 'An example of a windows service in Python'

    @classmethod
    def parse_command_line(cls):
        win32serviceutil.HandleCommandLine(cls)

    def __init__(self, args):
        win32serviceutil.ServiceFramework.__init__(self, args)
        self.stopEvt = win32event.CreateEvent(None, 0, 0, None)  # create generic event
        socket.setdefaulttimeout(60)

    def SvcStop(self):
        servicemanager.LogMsg(servicemanager.EVENTLOG_INFORMATION_TYPE,
                            servicemanager.PYS_SERVICE_STOPPED,
                            (self._svc_name_, ''))
        self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING)
        win32event.SetEvent(self.stopEvt)  # raise event

    def SvcDoRun(self):
        servicemanager.LogMsg(servicemanager.EVENTLOG_INFORMATION_TYPE,
                            servicemanager.PYS_SERVICE_STARTED,
                            (self._svc_name_, ''))
        # UNCOMMENT ONE OF THESE
        # self.mainthread()
        # self.mainloop()

    # Wait for stopEvt indefinitely after starting thread.
    def mainthread(self):
        print('main start')
        self.server = MyThread()
        self.server.start()
        print('wait for win32event')
        win32event.WaitForSingleObject(self.stopEvt, win32event.INFINITE)
        self.server.exit()
        print('wait for thread')
        self.server.join()
        print('main done')

    # Wait for stopEvt event in loop.
    def mainloop(self):
        print('loop start')
        rc = None
        while rc != win32event.WAIT_OBJECT_0:
            dummytask_once()
            rc = win32event.WaitForSingleObject(self.stopEvt, 3000)
        print('loop done')


if __name__ == '__main__':
    SMWinservice.parse_command_line()

https://www.chrisumbel.com/article/windows_services_in_python

跟踪PySvc.py 更改DLL文件夹

我知道这很旧了,但我一直都困在这上面。对我来说,这个特定的问题是通过复制这个文件pywintypes36.dll解决的

号码

To -> Python36\Lib\site-packages\win32

setx /M PATH "%PATH%;C:\Users\user\AppData\Local\Programs\Python\Python38-32;C:\Users\user\AppData\Local\Programs\Python\Python38-32\Scripts;C:\Users\user\AppData\Local\Programs\Python\Python38-32\Lib\site-packages\pywin32_system32;C:\Users\user\AppData\Local\Programs\Python\Python38-32\Lib\site-packages\win32

将路径更改为python文件夹

cd C:\Users\user\AppData\Local\Programs\Python\ Python38-32

NET START PySvc NET STOP PySvc


这个答案是从StackOverflow上的几个来源抄袭的——上面大部分都是,但我已经忘记了其他的——对不起。它很简单,脚本可以“按原样”运行。对于发布,您测试脚本,然后将其复制到服务器并停止/启动相关的服务。它应该适用于所有脚本语言(Python, Perl, node.js),加上批处理脚本,如GitBash, PowerShell,甚至旧的DOS bat脚本。 pyGlue是位于Windows服务和脚本之间的胶水。

'''
A script to create a Windows Service, which, when started, will run an executable with the specified parameters.
Optionally, you can also specify a startup directory

To use this script you MUST define (in class Service)
1. A name for your service (short - preferably no spaces)
2. A display name for your service (the name visibile in Windows Services)
3. A description for your service (long details visible when you inspect the service in Windows Services)
4. The full path of the executable (usually C:/Python38/python.exe or C:WINDOWS/System32/WindowsPowerShell/v1.0/powershell.exe
5. The script which Python or PowerShell will run(or specify None if your executable is standalone - in which case you don't need pyGlue)
6. The startup directory (or specify None)
7. Any parameters for your script (or for your executable if you have no script)

NOTE: This does not make a portable script.
The associated '_svc_name.exe' in the dist folder will only work if the executable,
(and any optional startup directory) actually exist in those locations on the target system

Usage: 'pyGlue.exe [options] install|update|remove|start [...]|stop|restart [...]|debug [...]'
Options for 'install' and 'update' commands only:
        --username domain\\username : The Username the service is to run under
        --password password : The password for the username
        --startup [manual|auto|disabled|delayed] : How the service starts, default = manual
        --interactive : Allow the service to interact with the desktop.
        --perfmonini file: .ini file to use for registering performance monitor data
        --perfmondll file: .dll file to use when querying the service for performance data, default = perfmondata.dll
Options for 'start' and 'stop' commands only:
        --wait seconds: Wait for the service to actually start or stop.
                If you specify --wait with the 'stop' option, the service and all dependent services will be stopped,
                each waiting the specified period.
'''

# Import all the modules that make life easy
import servicemanager
import socket
import sys
import win32event
import win32service
import win32serviceutil
import win32evtlogutil
import os
from logging import Formatter, Handler
import logging
import subprocess


# Define the win32api class
class Service (win32serviceutil.ServiceFramework):
        # The following variable are edited by the build.sh script
        _svc_name_ = "TestService"
        _svc_display_name_ = "Test Service"
        _svc_description_ = "Test Running Python Scripts as a Service"
        service_exe = 'c:/Python27/python.exe'
        service_script = None
        service_params = []
        service_startDir = None

        # Initialize the service
        def __init__(self, args):
                win32serviceutil.ServiceFramework.__init__(self, args)
                self.hWaitStop = win32event.CreateEvent(None, 0, 0, None)
                self.configure_logging()
                socket.setdefaulttimeout(60)

        # Configure logging to the WINDOWS Event logs
        def configure_logging(self):
                self.formatter = Formatter('%(message)s')
                self.handler = logHandler()
                self.handler.setFormatter(self.formatter)
                self.logger = logging.getLogger()
                self.logger.addHandler(self.handler)
                self.logger.setLevel(logging.INFO)

        # Stop the service
        def SvcStop(self):
                self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING)
                win32event.SetEvent(self.hWaitStop)

        # Run the service
        def SvcDoRun(self):
                self.main()

        # This is the service
        def main(self):

                # Log that we are starting
                servicemanager.LogMsg(servicemanager.EVENTLOG_INFORMATION_TYPE, servicemanager.PYS_SERVICE_STARTED,
                                                          (self._svc_name_, ''))

                # Fire off the real process that does the real work
                logging.info('%s - about to call Popen() to run %s %s %s', self._svc_name_, self.service_exe, self.service_script, self.service_params)
                self.process = subprocess.Popen([self.service_exe, self.service_script] + self.service_params, shell=False, cwd=self.service_startDir)
                logging.info('%s - started process %d', self._svc_name_, self.process.pid)

                # Wait until WINDOWS kills us - retrigger the wait for stop every 60 seconds
                rc = None
                while rc != win32event.WAIT_OBJECT_0:
                        rc = win32event.WaitForSingleObject(self.hWaitStop, (1 * 60 * 1000))

                # Shut down the real process and exit
                logging.info('%s - is terminating process %d', self._svc_name_, self.process.pid)
                self.process.terminate()
                logging.info('%s - is exiting', self._svc_name_)


class logHandler(Handler):
        '''
Emit a log record to the WINDOWS Event log
        '''

        def emit(self, record):
                servicemanager.LogInfoMsg(record.getMessage())


# The main code
if __name__ == '__main__':
        '''
Create a Windows Service, which, when started, will run an executable with the specified parameters.
        '''

        # Check that configuration contains valid values just in case this service has accidentally
        # been moved to a server where things are in different places
        if not os.path.isfile(Service.service_exe):
                print('Executable file({!s}) does not exist'.format(Service.service_exe), file=sys.stderr)
                sys.exit(0)
        if not os.access(Service.service_exe, os.X_OK):
                print('Executable file({!s}) is not executable'.format(Service.service_exe), file=sys.stderr)
                sys.exit(0)
        # Check that any optional startup directory exists
        if (Service.service_startDir is not None) and (not os.path.isdir(Service.service_startDir)):
                print('Start up directory({!s}) does not exist'.format(Service.service_startDir), file=sys.stderr)
                sys.exit(0)

        if len(sys.argv) == 1:
                servicemanager.Initialize()
                servicemanager.PrepareToHostSingle(Service)
                servicemanager.StartServiceCtrlDispatcher()
        else:
                # install/update/remove/start/stop/restart or debug the service
                # One of those command line options must be specified
                win32serviceutil.HandleCommandLine(Service)

现在有一些编辑,你不希望你所有的服务都叫“pyGlue”。所以有一个脚本(build.sh)来插入比特并创建一个自定义的“pyGlue”和创建一个“。exe”。就是这个“。exe”被安装为Windows服务。安装后,您可以将其设置为自动运行。

#!/bin/sh
# This script build a Windows Service that will install/start/stop/remove a service that runs a script
# That is, executes Python to run a Python script, or PowerShell to run a PowerShell script, etc

if [ $# -lt 6 ]; then
        echo "Usage: build.sh Name Display Description Executable Script StartupDir [Params]..."
        exit 0
fi

name=$1
display=$2
desc=$3
exe=$4
script=$5
startDir=$6
shift; shift; shift; shift; shift; shift
params=
while [ $# -gt 0 ]; do
        if [ "${params}" != "" ]; then
                params="${params}, "
        fi
        params="${params}'$1'"
        shift
done

cat pyGlue.py | sed -e "s/pyGlue/${name}/g" | \
        sed -e "/_svc_name_ =/s?=.*?= '${name}'?" | \
        sed -e "/_svc_display_name_ =/s?=.*?= '${display}'?" | \
        sed -e "/_svc_description_ =/s?=.*?= '${desc}'?" | \
        sed -e "/service_exe =/s?=.*?= '$exe'?" | \
        sed -e "/service_script =/s?=.*?= '$script'?" | \
        sed -e "/service_params =/s?=.*?= [${params}]?" | \
        sed -e "/service_startDir =/s?=.*?= '${startDir}'?" > ${name}.py

cxfreeze ${name}.py --include-modules=win32timezone

安装-复制'.exe'服务器和脚本到指定的文件夹。以管理员身份运行“。exe”,并选择“install”。以管理员身份打开Windows服务,并启动服务。若要升级,只需复制新版本的脚本并停止/启动服务。

现在每个服务器都是不同的——不同的Python安装,不同的文件夹结构。我为每个服务器维护一个文件夹,其中包含pyGlue.py和build.sh的副本。我创建了一个'serverBuild.sh'脚本,用于重建该服务器上的所有服务。

# A script to build all the script based Services on this PC
sh build.sh AutoCode 'AutoCode Medical Documents' 'Autocode Medical Documents to SNOMED_CT and AIHW codes' C:/Python38/python.exe autocode.py C:/Users/russell/Documents/autocoding -S -T

这并没有回答最初的问题,但可能会帮助其他想要在Windows启动时自动启动Python脚本的人: 看看Windows任务调度程序,如果你只是想在启动后启动一个脚本,而不需要Windows服务的所有服务功能,它会更容易。

创建一个新任务,选择“At startup”作为触发器,选择“Start program”作为动作,程序为“C:\Python39\python.exe”(或任何python.exe所在的位置),脚本的完整路径(“C:…\my_dir\xyz.py”)作为参数(如果路径包含空格,则可以使用“”)。 你也可以选择你的脚本的路径(没有.py文件,例如。"C:…\my_dir")如果你在你的脚本中使用相对路径,例如日志。