我有一个解决方案,但它相当丑陋。
当按下Ctrl+C时,Python会接收到一个中断信号(SIGINT),该信号会在您的进程树中传播。Python还会生成一个KeyboardInterrupt,因此您可以尝试处理与您的进程逻辑绑定的内容,但与子进程耦合的逻辑无法受到影响。
要影响传递给子进程的信号,您必须在通过subprocess.Popen
生成进程之前指定如何处理信号。
有各种选项,这个选项来自另一个答案:
import subprocess
import signal
def preexec_function():
signal.signal(signal.SIGINT, signal.SIG_IGN)
my_process = subprocess.Popen(
["my_executable"],
preexec_fn = preexec_function
)
问题在于,你没有调用
Popen
,而是
委托给selenium。关于这个问题,有
各种讨论。据我所知,其他试图影响信号屏蔽的解决方案在屏蔽操作没有在调用
Popen
之前执行时容易失败。
此外,请记住,Python文档中有一个
关于使用preexec_fn的重要警告,因此请自行决定是否使用它。
“幸运的是”,Python允许在运行时覆盖函数,因此我们可以这样做:
>>> import monkey
>>> import selenium.webdriver
>>> selenium.webdriver.common.service.Service.start = monkey.start
>>> ffx = selenium.webdriver.Firefox()
>>>
KeyboardInterrupt
>>> ffx.service.assert_process_still_running()
>>> ffx.quit()
>>> ffx.service.assert_process_still_running()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/lib/python3.6/site-packages/selenium/webdriver/common/service.py", line 107, in assert_process_still_running
return_code = self.process.poll()
AttributeError: 'NoneType' object has no attribute 'poll'
如下所示,使用 monkey.py:
import errno
import os
import platform
import subprocess
from subprocess import PIPE
import signal
import time
from selenium.common.exceptions import WebDriverException
from selenium.webdriver.common import utils
def preexec_function():
signal.signal(signal.SIGINT, signal.SIG_IGN)
def start(self):
"""
Starts the Service.
:Exceptions:
- WebDriverException : Raised either when it can't start the service
or when it can't connect to the service
"""
try:
cmd = [self.path]
cmd.extend(self.command_line_args())
self.process = subprocess.Popen(cmd, env=self.env,
close_fds=platform.system() != 'Windows',
stdout=self.log_file,
stderr=self.log_file,
stdin=PIPE,
preexec_fn=preexec_function)
except TypeError:
raise
except OSError as err:
if err.errno == errno.ENOENT:
raise WebDriverException(
"'%s' executable needs to be in PATH. %s" % (
os.path.basename(self.path), self.start_error_message)
)
elif err.errno == errno.EACCES:
raise WebDriverException(
"'%s' executable may have wrong permissions. %s" % (
os.path.basename(self.path), self.start_error_message)
)
else:
raise
except Exception as e:
raise WebDriverException(
"The executable %s needs to be available in the path. %s\n%s" %
(os.path.basename(self.path), self.start_error_message, str(e)))
count = 0
while True:
self.assert_process_still_running()
if self.is_connectable():
break
count += 1
time.sleep(1)
if count == 30:
raise WebDriverException("Can not connect to the Service %s" % self.path)
这段代码是从Selenium开始的(链接),高亮显示的部分是添加的一行代码。
这是一个简陋的hack,可能会有问题。祝好运:D
except
语句中包含了非常通用和广泛的异常类Exception
。尝试将自己限制在KeyboardInterrupt
上,看看是否有效。 - Abhinav