如何确保Selenium脚本B在所有场景下执行driver.quit()?
问题背景
我通过Python脚本A的subprocess.Popen启动了运行Selenium自动化的Python脚本B。脚本B运行时存在三种场景:
- 脚本B正常完成任务;
- 脚本B执行时崩溃;
- 脚本A调用
taskkill终止脚本B。
已知场景1可在末尾调用driver.quit(),场景2可使用try-except-finally处理,但场景3下,脚本A用以下代码强制终止B时,怎么确保B能执行driver.quit()?
subprocess.call(['taskkill', '/F', '/T', '/PID', str(processB.pid)])
解决思路与实现方法
首先明确:taskkill /F是强制终止进程,这种情况下脚本B会被直接杀死,根本没机会执行任何收尾代码。核心解决思路是避免硬终止,改成让脚本B主动响应终止信号并执行清理,或者用兜底的监控方案。
方案1:改用软终止信号(推荐)
把强制终止改成发送可捕获的终止信号,让脚本B有机会执行driver.quit()。
脚本A的修改
替换原来的taskkill /F调用,改成发送Ctrl+C对应的控制台信号(Windows环境):
import win32api import win32con # 给脚本B发送Ctrl+C信号,触发其信号处理逻辑 win32api.GenerateConsoleCtrlEvent(win32con.CTRL_C_EVENT, processB.pid) # 等待脚本B自行完成退出 processB.wait() # 如果上述方法无效,可降级为非强制的taskkill(不加/F参数) # subprocess.call(['taskkill', '/T', '/PID', str(processB.pid)])
脚本B的修改
在脚本B中注册信号处理函数,捕获终止信号并执行浏览器清理:
import signal from selenium import webdriver driver = None def clean_up(signum, frame): global driver if driver: driver.quit() exit(0) # 注册信号处理:捕获Ctrl+C(SIGINT)和通用终止信号(SIGTERM) signal.signal(signal.SIGINT, clean_up) signal.signal(signal.SIGTERM, clean_up) try: driver = webdriver.Chrome() # 你的Selenium自动化业务逻辑 finally: # 覆盖正常结束和崩溃场景的清理 if driver: driver.quit()
方案2:强制终止下的兜底监控(仅万不得已时用)
如果必须用taskkill /F,可以在脚本B中启动一个独立的监控子进程,当检测到B的主进程被杀死后,负责关闭浏览器驱动。
脚本B的实现
import os from selenium import webdriver import subprocess driver = webdriver.Chrome() current_pid = os.getpid() # 获取浏览器驱动的进程PID driver_pid = driver.service.process.pid # 启动监控脚本,传入主进程PID和驱动PID subprocess.Popen(['python', 'monitor.py', str(current_pid), str(driver_pid)]) try: # 你的自动化逻辑 finally: if driver: driver.quit()
监控脚本monitor.py的实现
import os import time import sys import subprocess def main(): parent_pid = int(sys.argv[1]) driver_pid = int(sys.argv[2]) while True: try: # 检查主进程是否存活 os.kill(parent_pid, 0) except OSError: # 主进程已死,强制关闭浏览器驱动 subprocess.call(['taskkill', '/F', '/PID', str(driver_pid)]) break time.sleep(1) if __name__ == "__main__": main()
关键提醒
- 尽量不要用
taskkill /F,硬终止等于直接断电,任何进程都没法执行收尾代码; - 方案2的监控脚本是兜底方案,缺点是多启动了一个进程,且依赖浏览器驱动PID的正确获取。
内容的提问来源于stack exchange,提问作者Gordian
相关产品推荐
相关产品推荐

