Selenium留下了运行过程?

时间:2016-07-22 05:43:16

标签: python python-2.7 selenium selenium-webdriver selenium-chromedriver

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

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

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://stackoverflow.com")
browser.find_element_by_id('...').click()

browser.close()

有时,浏览器无法足够快地加载网页元素,因此当Selenium尝试点击它找不到的内容时会崩溃。其他时候它工作正常。

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

6 个答案:

答案 0 :(得分:3)

每次Selenium在Chrome上运行时,Chromedriver.exe都会占用TaskManager(如果是Windows)。有时,即使浏览器没有崩溃,它也不会清除。

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

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

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

答案 1 :(得分:3)

发生的事情是你的代码抛出异常,暂停python进程继续。因此,close / quit方法永远不会在浏览器对象上调用,因此chromedrivers只是无限期地挂起。

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

from selenium import webdriver

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

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

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

答案 2 :(得分:1)

我看到了这个相当古老的线程,但是也许我的情况对某人有用。 由于某些原因,对于带有Xvfb的Docker容器中的每个请求,我不得不使用带有headfull(非headless)浏览器的单独的webdriver实例运行大量抓取工具。因此,每个请求都会使用Firefox生成2-3个僵尸进程。 (和12个Chromedriver)。 因此,经过几分钟的刮擦,我经历了成千上万的僵尸进程。 driver.close()driver.quit()没有成功。 Jimmy's Engelbrecht解决方案更好,但仅杀死了部分进程。 因此,对我而言,唯一可行的方法是在Docker容器中启用init

docker run --init container

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

答案 3 :(得分:0)

正如已经指出的,您应该运行browser.quit()

但是在linux上(在docker内部),这将留下已失效的进程。这些通常不是真正的问题,因为它们仅是过程表中的一项,并且不消耗资源。但是,如果您有很多,您将不会失去流程。通常,我的服务器在65,000个进程中崩溃。

它看起来像这样:

# 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))
    except ChildProcessError:
        pass

答案 4 :(得分:0)

我遇到了同样的问题:在 docker 中运行 chromedriver。但是当调用 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"]

入口点.sh:

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

ENTRYPOINTexec 在 docker 中非常重要。

答案 5 :(得分:-2)

我遇到了同样的问题:在 docker 中运行 chromedriver。但是当调用 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"]

入口点.sh:

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

ENTRYPOINTexec 在 docker 中非常重要。