简体   繁体   English

如何停止由 selenium 远程驱动程序启动的 chrome?

[英]How to stop chrome launched by selenium remote driver?

First, I'm using Django, and I'm building an API.首先,我正在使用 Django,并且我正在构建一个 API。 For example, I've route like api/get-some-element .例如,我的路由类似于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)

On the first access to that route, it will send a task to Celery to launch Selenium Headless Chrome (main chrome).在第一次访问该路由时,它会向 Celery 发送一个任务来启动 Selenium Headless Chrome(主 Chrome)。 Why I'm using Celery?为什么我使用芹菜? Because I need to make Chrome always running.因为我需要让 Chrome 始终运行。 (Idk better way, this is what I know). (我知道更好的方法,这就是我所知道的)。

Then, for the next access on that route, it will response with Waiting chrome to launched.然后,对于该路线的下一次访问,它将响应Waiting chrome to launched. , until the Celery task got executed (chrome launched properly). , 直到 Celery 任务被执行(chrome 正常启动)。

After main chrome is launched, then it will launch Selenium Headless Remote Driver immediately (without Celery), the purpose of this remote driver is to access the main chrome.启动主chrome后,它会立即启动Selenium Headless Remote Driver(没有Celery),这个远程驱动的目的是访问主chrome。 Then, it just grab some element from a website.然后,它只是从网站上抓取一些元素。

But, after finish, the Remote Driver is still running.但是,完成后,远程驱动程序仍在运行。 How to stop that?怎么阻止?

I know the command such as driver.quit() or driver.close() .我知道诸如driver.quit()driver.close()类的命令。 But, as far as I know, it's send the command to the main chrome, not to the chrome launched by remote driver.但是,据我所知,它是将命令发送到主 chrome,而不是远程驱动程序启动的 chrome。 And that's not what I want.这不是我想要的。 I don't want to quit the main chrome, just quit the chrome launched by remote driver.我不想退出主chrome,只是退出远程驱动程序启动的chrome。

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

The problem is with driver.quit() method only for Chrome.问题在于仅适用于 Chrome 的 driver.quit() 方法。 The driver quit didnt work properly it didnt kill all processes of chrome (including child processes).驱动程序退出无法正常工作,它没有杀死所有 chrome 进程(包括子进程)。 what you can do is change Selenium jar codes to fix this.您可以做的是更改 Selenium jar 代码来解决此问题。

or you can make use of finally block.或者你可以使用 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();
    }

Are you using multiple Chrome windows?您是否使用多个 Chrome 窗口?

driver.close should work, because it closes only the focused window. driver.close应该可以工作,因为它只关闭聚焦的窗口。 Maybe you should try:也许你应该尝试:

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

In this case, you should find the certain window to switch for.在这种情况下,您应该找到要切换的特定窗口。 Please, let me know if that works请让我知道这是否有效

You are starting an external process and want to stop it from another (not the one that started it) python process .您正在启动一个外部进程并希望从另一个(不是启动它的那个) python process停止它。 For this you can save process pid or name and kill it with os.kill(pid, signal.SIGKILL) or with similar alternatives .为此,您可以保存进程pidname ,并使用os.kill(pid, signal.SIGKILL)类似的替代方案杀死它。


You can also start chromedriver as a service :您还可以将chromedriver 作为服务启动

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

which uses subprocess.Popen at the back.在后面使用subprocess.Popen As you might be starting from one python process / celery worker and later stopping from another - save service.pid in cache / database / queue / etc and send signals to process pid directly, rather than doing service.stop() .因为您可能从一个 python 进程/celery worker 开始,然后从另一个进程停止 - 将service.pid保存在缓存/数据库/队列/等中,并直接发送信号以处理 pid,而不是执行service.stop()

One possible downside of killing process directly - it may not perform all clean-up tasks correctly (ie close opened sockets), it may hang, you may need more logic to control its status etc.直接杀死进程的一个可能的缺点 - 它可能无法正确执行所有清理任务(即关闭打开的套接字),它可能会挂起,您可能需要更多逻辑来控制其状态等。


Alternatives to control another process - are to rely on external service manager , like systemd or docker .控制另一个进程的替代方法是依赖外部服务管理器,如systemddocker This separates all process control logic in their configuration (service file or Dockerfile), makes easier to control that only one instance is run and much more.这在其配置(服务文件或 Dockerfile)中分离了所有流程控制逻辑,更容易控制仅运行一个实例等等。

  • launch chromedriver as system service with systemd as a service.使用 systemd 作为服务启动 chromedriver 作为系统服务。 You can control from python with ie pystemd您可以使用 ie pystemd从 python 进行控制
  • or if you are working with docker - launch chromedriver as docker container with docker-python或者,如果您正在使用 docker - 使用 docker -python 将chromedriver 作为 docker 容器启动

With these options you are telling external managers to start / stop service, not trying to control it from your app.使用这些选项,您是在告诉外部经理启动/停止服务,而不是试图从您的应用程序控制它。

In distributed environment you may want to make sure chromedriver is launched only on specific node - ie make only celery worker on it to listen to broker queue with chromedriver launch tasks or connect to docker engine on target node or use node_id / tag in swarm / k8s ...在分布式环境中,您可能希望确保 chromedriver 仅在特定节点上启动 - 即仅在其上使用 celery worker 来侦听具有 chromedriver 启动任务的代理队列或连接到目标节点上的 docker 引擎或在 swarm / k8s 中使用 node_id / tag ...

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM