Selenium 留下 运行 个进程?

Selenium leaves behind running processes?

当我的 selenium 程序由于某些错误而崩溃时,它似乎留下了 运行ning 进程。

例如,这是我的进程列表:

carol    30186  0.0  0.0 103576  7196 pts/11   Sl   00:45   0:00 /home/carol/test/chromedriver --port=51789
carol    30322  0.0  0.0 102552  7160 pts/11   Sl   00:45   0:00 /home/carol/test/chromedriver --port=33409
carol    30543  0.0  0.0 102552  7104 pts/11   Sl   00:48   0:00 /home/carol/test/chromedriver --port=42567
carol    30698  0.0  0.0 102552  7236 pts/11   Sl   00:50   0:00 /home/carol/test/chromedriver --port=46590
carol    30938  0.0  0.0 102552  7496 pts/11   Sl   00:55   0:00 /home/carol/test/chromedriver --port=51930
carol    31546  0.0  0.0 102552  7376 pts/11   Sl   01:16   0:00 /home/carol/test/chromedriver --port=53077
carol    31549  0.5  0.0      0     0 pts/11   Z    01:16   0:03 [chrome] <defunct>
carol    31738  0.0  0.0 102552  7388 pts/11   Sl   01:17   0:00 /home/carol/test/chromedriver --port=55414
carol    31741  0.3  0.0      0     0 pts/11   Z    01:17   0:02 [chrome] <defunct>
carol    31903  0.0  0.0 102552  7368 pts/11   Sl   01:19   0:00 /home/carol/test/chromedriver --port=54205
carol    31906  0.6  0.0      0     0 pts/11   Z    01:19   0:03 [chrome] <defunct>
carol    32083  0.0  0.0 102552  7292 pts/11   Sl   01:20   0:00 /home/carol/test/chromedriver --port=39083
carol    32440  0.0  0.0 102552  7412 pts/11   Sl   01:24   0:00 /home/carol/test/chromedriver --port=34326
carol    32443  1.7  0.0      0     0 pts/11   Z    01:24   0:03 [chrome] <defunct>
carol    32691  0.1  0.0 102552  7360 pts/11   Sl   01:26   0:00 /home/carol/test/chromedriver --port=36369
carol    32695  2.8  0.0      0     0 pts/11   Z    01:26   0:02 [chrome] <defunct>

这是我的代码:

from selenium import webdriver

browser = webdriver.Chrome("path/to/chromedriver")
browser.get("http://whosebug.com")
browser.find_element_by_id('...').click()

browser.close()

有时,浏览器加载网页元素的速度不够快,因此当 Selenium 尝试单击它未找到的内容时,它会崩溃。其他时候没问题。

为了简单起见,这是一个简单的示例,但是对于更复杂的 selenium 程序,什么是保证退出并且不留下 运行ning 进程的干净方式?它应该在意外崩溃和成功 运行.

时干净地退出

Chromedriver.exe 每次在 Chrome.Sometimes 上使用 Selenium 运行 时都会使 TaskManager(在 Windows 的情况下)拥挤,即使浏览器没有清除它也不会清除碰撞。

我通常 运行 一个 bat 文件或 cmd 来杀死所有现有的 chromedriver.exe 进程,然后再启动另一个进程。

看看这个:release Selenium chromedriver.exe from memory

  • 我知道这是一个与 Unix 相关的问题,但我确信 Windows 中处理它的方式可以应用到那里。

发生的情况是您的代码抛出异常,阻止 python 进程继续进行。因此,close/quit 方法永远不会在浏览器对象上调用,因此 chromedriver 会无限期地挂起。

您需要使用 try/except 块来确保每次都调用 close 方法,即使在抛出异常时也是如此。一个非常简单的例子是:

from selenium import webdriver

browser = webdriver.Chrome("path/to/chromedriver")
try:
    browser.get("http://whosebug.com")
    browser.find_element_by_id('...').click()

except:
    browser.close()
    browser.quit()  # I exclusively use quit

您可以在此处采用许多更复杂的方法,例如创建上下文管理器以与 with 语句一起使用,但如果不更好地了解您的代码库,很难推荐一种方法.

如前所述,您应该 运行 browser.quit()

但是在 linux(在 docker 内)这将留下不存在的进程。这些通常不是真正的问题,因为它们只是流程中的一个条目 -table 并且不消耗任何资源。但是如果你有很多这样的人,你会 运行 出流程。通常我的服务器在 65k 个进程时崩溃。

看起来像这样:

# root@dockerhost1:~/odi/docker/bf1# ps -ef | grep -i defunct | wc -l
28599

root@dockerhost1:~/odi/docker/bf1# ps -ef | grep -i defunct | tail
root     32757 10839  0 Oct18 ?        00:00:00 [chrome] <defunct>
root     32758   895  0 Oct18 ?        00:00:02 [chrome] <defunct>
root     32759 15393  0 Oct18 ?        00:00:00 [chrome] <defunct>
root     32760 13849  0 01:23 ?        00:00:00 [chrome] <defunct>
root     32761   472  0 Oct18 ?        00:00:00 [chrome] <defunct>
root     32762 19360  0 01:35 ?        00:00:00 [chrome] <defunct>
root     32763 30701  0 00:34 ?        00:00:00 [chrome] <defunct>
root     32764 17556  0 Oct18 ?        00:00:00 [chrome] <defunct>
root     32766  8102  0 00:49 ?        00:00:00 [cat] <defunct>
root     32767  9490  0 Oct18 ?        00:00:00 [chrome] <defunct>

下面的代码将解决问题:

def quit_driver_and_reap_children(driver):
    log.debug('Quitting session: %s' % driver.session_id)
    driver.quit()
    try:
        pid = True
        while pid:
            pid = os.waitpid(-1, os.WNOHANG)
            log.debug("Reaped child: %s" % str(pid))

            #Wonka's Solution to avoid infinite loop cause pid value -> (0, 0)
            try:
                if pid[0] == 0:
                    pid = False
            except:
                pass
            #---- ----

    except ChildProcessError:
        pass

我看到了这个很老的帖子,但也许我的案例对某些人有用。 由于某些原因,我不得不 运行 大量带有单独 webdriver 实例的爬虫,带有 headfull(非无头)浏览器,用于 Docker 带有 Xvfb 的容器中的每个请求。所以每个请求都会用 firefox 产生 2-3 个僵尸进程。 (和 12 个 Chromedriver)。 因此,经过几分钟的抓取,我有数千个僵尸进程。 driver.close()driver.quit() 没有成功。 解决方案更好,但它只终止了部分进程。 所以对我来说唯一可行的方法是在 docker 容器中启用 init

docker run --init container

它保护您免受意外创建僵尸进程的软件的侵害,僵尸进程可能(随着时间的推移!)使您的整个系统因 PID 而饿死(并使其无法使用)。

我遇到了同样的问题:运行 chromedriver in docker。但是当调用 quit() 时,chromedriver 变成了僵尸线程。 我用 dumb-init 来解决我的问题。我猜这个问题不仅仅出现在chromedriver中,它与docker的特性有关,它缺少Linux的一些组件,导致无法正确处理子线程。

Dockerfile 添加:

RUN wget https://github.com/Yelp/dumb-init/releases/download/v1.2.5/dumb-init_1.2.5_amd64.deb
RUN sudo dpkg -i dumb-init_*.deb
ENTRYPOINT ["/usr/bin/dumb-init", "--", "./entrypoint.sh"]

entrypoint.sh:

#!/bin/sh
echo "使用参数为 $*"
exec java -jar $JAR_NAME "$@"

ENTRYPOINTexec 在 docker.

中非常重要

我遇到了同样的问题:运行 chromedriver in docker。但是当调用 quit() 时,chromedriver 变成了僵尸线程。 我用 dumb-init 来解决我的问题。我猜这个问题不仅仅出现在chromedriver中,它与docker的特性有关,它缺少Linux的一些组件,导致无法正确处理子线程。

Dockerfile 添加:

RUN wget https://github.com/Yelp/dumb-init/releases/download/v1.2.5/dumb-init_1.2.5_amd64.deb
RUN sudo dpkg -i dumb-init_*.deb
ENTRYPOINT ["/usr/bin/dumb-init", "--", "./entrypoint.sh"]

entrypoint.sh:

#!/bin/sh
echo "使用参数为 $*"
exec java -jar $JAR_NAME "$@"

ENTRYPOINTexec 在 docker.

中非常重要