You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

多进程下点击终止按钮无法关闭Selenium WebDriver浏览器的问题

问题

启动程序点击按钮后,爬取和进程终止功能正常,但浏览器无法关闭。需求是点击终止按钮时关闭浏览器,但不想直接调用self.browser.quit()。

现有代码:

Wrapper类代码

class Wrapper(Process):
    def __init__(self):
        self.crawler = self.Cralwer()
        super().__init__(target=self.crawler.start_crawling)

    def starter(self):
        self.start()

    def exit(self):
        self.terminate()

    class Cralwer:
        def __del__(self) -> None:
            try:
                self.browser.quit()
            except:
                pass

        def start_crawling(self):
            service = Service(EdgeChromiumDriverManager().install())
            self.browser = Edge(service=service, options=options)

            while True:
                # ~爬取代码~
                pass

Tkinter入口代码

def entry_point():
    global processor

    try:
        processor.starter()
    except AssertionError:
        processor = Wrapper()
        processor.starter()


def force_close_crawling():
    global processor

    try:
        processor.exit()
    except AttributeError:
        pass


if __name__ == "__main__":
    app = tkinter.Tk()
    processor = Wrapper()
    btn1 = tkinter.Button(app, text='run', command=entry_point)
    btn2 = tkinter.Button(app, text='terminate', command=force_close_crawling)
    btn1.pack()
    btn2.pack()

    app.mainloop()
原因

调用Process.terminate()是强制终止进程,这种情况下子进程的析构方法__del__不会被Python解释器正常执行,所以浏览器进程无法被关闭。

解决方案

使用进程间通信让爬虫进程优雅退出,触发__del__方法自动关闭浏览器:

  • 在Wrapper类中添加一个multiprocessing.Event对象作为退出信号
  • 将信号传递给内部的Crawler类
  • 修改start_crawling的循环逻辑,每次循环检查退出信号,收到信号就终止循环
  • 修改exit方法,不再强制杀进程,而是设置退出信号并等待进程结束
修改后的代码

Wrapper类修改版

from multiprocessing import Process, Event
# 其他导入保持不变

class Wrapper(Process):
    def __init__(self):
        self.exit_event = Event()  # 退出信号事件
        self.crawler = self.Crawler(self.exit_event)  # 传递信号给爬虫
        super().__init__(target=self.crawler.start_crawling)

    def starter(self):
        # 启动前重置退出信号,避免重复启动时信号处于触发状态
        self.exit_event.clear()
        self.start()

    def exit(self):
        self.exit_event.set()  # 发送退出信号
        self.join()  # 等待进程优雅结束

    class Crawler:
        def __init__(self, exit_event: Event):
            self.exit_event = exit_event

        def __del__(self) -> None:
            try:
                self.browser.quit()
                print("浏览器已关闭")
            except Exception as e:
                print(f"关闭浏览器时出错: {e}")

        def start_crawling(self):
            service = Service(EdgeChromiumDriverManager().install())
            self.browser = Edge(service=service, options=options)

            while True:
                # 检查退出信号,若触发则终止循环
                if self.exit_event.is_set():
                    break
                
                # ~爬取代码~
                # 可在爬取逻辑的适当位置增加信号检查,比如每次请求后
                pass

Tkinter代码无需修改

原Tkinter入口代码保持不变即可,force_close_crawling调用的processor.exit()已改为优雅退出逻辑。

说明
  • 用Event实现进程间通信,主进程通过设置事件通知子进程退出
  • 子进程在循环中检查事件,收到信号后跳出循环,进程结束时自动触发__del__方法关闭浏览器
  • 完全避免了直接调用self.browser.quit(),符合需求

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.20 22:52:49