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 而饿死(并使其无法使用)。
- 如果您使用
docker-compose
,您可以按照 中的描述启用它
- 对于 Docker < 1.13,您可以手动实施 https://github.com/krallin/tini。
我遇到了同样的问题:运行 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 "$@"
ENTRYPOINT 和 exec 在 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 "$@"
ENTRYPOINT 和 exec 在 docker.
中非常重要
当我的 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()
没有成功。
init
。
docker run --init container
它保护您免受意外创建僵尸进程的软件的侵害,僵尸进程可能(随着时间的推移!)使您的整个系统因 PID 而饿死(并使其无法使用)。
- 如果您使用
docker-compose
,您可以按照 中的描述启用它
- 对于 Docker < 1.13,您可以手动实施 https://github.com/krallin/tini。
我遇到了同样的问题:运行 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 "$@"
ENTRYPOINT 和 exec 在 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 "$@"
ENTRYPOINT 和 exec 在 docker.
中非常重要