【问题标题】:How to stop chrome launched by selenium remote driver?如何停止由 selenium 远程驱动程序启动的 chrome?
【发布时间】:2020-04-18 12:38:46
【问题描述】:

首先,我正在使用 Django,并且正在构建一个 API。例如,我的路线类似于api/get-some-element

browser_url = cache.get('user_%d.browser_url' % user_id)
is_browser_queued = cache.get('user_%d.browser_queued' % user_id)
browser_session_id = cache.get('user_%d.browser_session_id' % user_id) # session id of the main chrome

if browser_url:
    capabilities = DesiredCapabilities.CHROME.copy()
    driver = webdriver.Remote(
        command_executor=browser_url,
        desired_capabilities=capabilities,
        options=options,
    )
    driver.session_id = browser_session_id

    return driver

if not is_browser_queued:
    run_browser.delay(user_id) # launch main chrome
    cache.set('user_%d.browser_queued' % user_id, True, None)

在第一次访问该路由时,它将向 Celery 发送一个任务以启动 Selenium Headless Chrome(主 chrome)。为什么我用芹菜?因为我需要让 Chrome 始终运行。 (我知道更好的方法,这就是我所知道的)。

然后,对于该路由上的下一次访问,它将以Waiting chrome to launched. 响应,直到 Celery 任务被执行(chrome 正确启动)。

主 chrome 启动后,它会立即启动 Selenium Headless Remote Driver(没有 Celery),这个远程驱动的目的是访问主 chrome。然后,它只是从网站中抓取一些元素。

但是,完成后,远程驱动程序仍在运行。如何阻止它?

我知道诸如driver.quit()driver.close() 之类的命令。但是,据我所知,它将命令发送到主 chrome,而不是远程驱动程序启动的 chrome。这不是我想要的。我不想退出主chrome,只退出远程驱动程序启动的chrome。

【问题讨论】:

  • 假设您的两个 chrome 都使用相同的 chromedriver(server) 打开。存储由您所指的“远程驱动程序”创建的会话 ID。 someremotesession = driver.session_id 。在此行之前 driver.session_id = browser_session_id 。在再次调用 quit 之前更改 driver.session_id = someremotesession 并调用 quit() 。您的“远程驱动程序”chrome 应该退出。
  • @RahulL 你是对的。这就是我现在所做的(我的意思是在你提出那个解决方案之前)。
  • 对不起任何人,我想我自己已经得到了答案。下次我会发布解决方案..

标签: python django selenium google-chrome celery


【解决方案1】:

您正在启动一个外部进程并希望停止从另一个(不是启动它的那个)python 进程。为此,您可以保存进程 pidname 并使用 os.kill(pid, signal.SIGKILL)similar alternatives 杀死它。


你也可以start chromedriver as a service:

service = Service('/path/to/chromedriver')
service.start()
...
service.stop()

在后面使用subprocess.Popen。因为您可能从一个 python 进程 / celery worker 开始,然后从另一个停止 - 将 service.pid 保存在缓存 / 数据库 / 队列 / 等中并直接发送信号到进程 pid,而不是执行 service.stop()

直接杀死进程的一个可能缺点 - 它可能无法正确执行所有清理任务(即关闭打开的套接字),它可能会挂起,您可能需要更多逻辑来控制其状态等。


控制另一个进程的替代方法 - 依赖外部服务管理器,例如 systemddocker。这将其配置(服务文件或 Dockerfile)中的所有流程控制逻辑分开,更容易控制仅运行一个实例等等。

  • 启动 chromedriver 作为系统服务,并将 systemd 作为服务。您可以使用 python 进行控制,即pystemd
  • 或者如果您正在使用 docker - 使用docker-python 将 chromedriver 作为 docker 容器启动

使用这些选项,您是在告诉外部经理启动/停止服务,而不是试图从您的应用中控制它。

在分布式环境中,您可能希望确保 chromedriver 仅在特定节点上启动 - 即仅在其上设置 celery worker 以侦听带有 chromedriver 启动任务的代理队列或连接到目标节点上的 docker 引擎或使用 node_id / tag in群/k8s ...

【讨论】:

    【解决方案2】:

    您是否使用多个 Chrome 窗口?

    driver.close 应该可以工作,因为它只关闭焦点窗口。 也许你应该试试:

    driver.switch_to.window(driver.window_handles[1])
    driver.close()
    

    在这种情况下,您应该找到要切换的特定窗口。 请让我知道这是否有效

    【讨论】:

      【解决方案3】:

      问题在于仅适用于 Chrome 的 driver.quit() 方法。驱动程序退出没有正常工作它没有杀死 chrome 的所有进程(包括子进程)。您可以做的是更改 Selenium jar 代码来解决此问题。

      或者你可以使用 finally 块。

      System.setProperty("webdriver.chrome.driver","/<path to chrome driver>/chromedriver");
          ChromeOptions options = new ChromeOptions();
          options.setBinary(new File("/<path to chrome >/google-chrome"));
          driver = new ChromeDriver(options);
          try
          {
              //automated steps
          }
          finally
          {
              driver.quit();
          }
      

      【讨论】:

        【解决方案4】:

        driver.close(), driver.quit() , driver.close 关闭当前窗口, driver.quit 关闭所有窗口,另外我强烈建议你不要使用 selenium ,它很慢而且是一样的可以通过请求来实现

        【讨论】:

        • 感谢您的回答。你有没有尝试过你的建议?我知道那个命令,但是,它将命令发送到主 chrome,而不是远程驱动程序。我的意思是,它是 quit 主 chrome,而不是远程驱动程序。
        • 对不起,我只是在我的问题中举一个例子,而不是真正的例子。不,就我而言,使用请求或 urllib 是不可能的。因为它需要与 javascripts 交互。
        • 您可以使用请求执行 JavaScript @nmfzone
        • 你试过吗?顺便说一句,我用过。然后告诉我如何..例如,在该页面上执行 jQuery..
        猜你喜欢
        • 2015-09-17
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-07-09
        • 2012-02-12
        • 2022-01-28
        • 1970-01-01
        • 2017-03-10
        相关资源
        最近更新 更多