首页 > 解决方案 > Python 3 Selenium WebDriverWait 导致脚本永远挂起/冻结

问题描述

我有一个使用 selenium webdriver (geckodriver) 并加载各种网页的脚本。这些脚本在开始时运行良好,但在随机点它停止工作而不会引发任何错误(程序有点挂起而没有真正做任何事情)。

我添加了一些日志语句来检查它何时挂起,这是由 WebDriverWait 语句引起的(见下文)。日志中打印的最后一件事是“get_records - Loaded”。

对我来说,预期的行为是打印“get_records - Acquired pager”,或者在 10 秒后引发 TimeoutException。

[...]
logging.info("get_records - Getting url: {}".format(url))
driver.get(url)
logging.info("get_records - Loaded")
# Get records number and result pages
elem = WebDriverWait(driver, 10).until(ec.element_to_be_clickable(
    (By.XPATH, "//td[@align='right']/span[@class='pager']"))
)
logging.info("get_records - Acquired pager")
[...]

Python 版本:3.7.3 Selenium 版本:3.141.0 Firefox 版本:70.0.1

以前的版本( Selenium WebDriver (2.25) Timeout Not Working )似乎发生了类似的错误,但该错误已关闭。

有没有人有同样的问题?

更新:

似乎time.sleep(0.5)在 elem 之前添加可以防止脚本冻结(打印“get_records - Acquired pager”,或者引发 timeoutException)。即使这是问题的好转,我宁愿不要强迫等待。

标签: pythonseleniumwebdriverwait

解决方案


当脚本起初运行良好但一段时间后永远挂起时,我实际上有完全相同的体验。“10 秒”超时是 webdriver/浏览器尝试在 10 秒内打开页面。但是没有定义 python 脚本向 webdriver/browser 发送请求的超时时间。默认情况下没有,这意味着请求将无限等待。

简短的回答:

driver.command_executor.set_timeout(10)
driver.get(url)

解释:

以 Chrome 驱动程序为例。每当您运行 selenium 脚本时。一个名为“chromedriver”的进程也会启动。我们称之为“控制过程”。它打开浏览器并控制它。它还充当一个 http 服务器,您可以通过它获取地址和端口driver.command_executor._url。它接收http请求,处理它,告诉浏览器做某事(可能打开一个url)并返回。详情在这里

你打电话时

elem = WebDriverWait(driver, 10).until(ec.element_to_be_clickable(
    (By.XPATH, "//td[@align='right']/span[@class='pager']"))
)

您实际上是在向作为 http 服务器的“控制进程”发送请求,并告诉它做某事(在当前页面中查找一些元素)。超时'10'意味着'控制进程'告诉浏览器在取消之前10秒内打开一个页面并将超时状态返回给python脚本。

但这里真正发生的是“控制过程”正在接收请求但没有响应。我真的不知道“控制过程”中发生了什么。

Python selenium 包urllib3.request用于发送请求并socket._GLOBAL_DEFAULT_TIMEOUT作为超时。默认情况下没有使请求无限等待。所以你可以使用driver.command_executor.set_timeout(10). 现在,如果“控制过程”中断,您将收到超时异常,并可能重新创建 webdriver。


推荐阅读