python - Selenium 在执行一段时间后为所有网站提供“超时接收来自渲染器的消息”
问题描述
我有一个应用程序,我需要一个长时间运行的Selenium Web 驱动程序实例(我在无头模式下使用Chrome 驱动程序 83.0.4103.39)。基本上,该应用程序不断从队列中提取 url-data 并将提取的 url 提供给 Selenium,Selenium 应该在网站上执行一些分析。其中许多网站可能已关闭、无法访问或损坏,因此我设置了 10 秒的页面加载超时,以避免 Selenium 永远等待页面加载。
我在这里遇到的问题是,经过一段时间的执行时间(比如说 10 分钟),Selenium 开始给出Timed out receiving message from renderer
每个网址的错误。最初它工作正常,它正确打开了好的网站并在坏的网站上超时(网站无法加载),但一段时间后它开始在所有内容上超时,即使是应该正确打开的网站(我已经检查过,它们在 Chrome 浏览器上正确打开)。我很难调试这个问题,因为应用程序中的每个异常都被正确捕获。我也注意到这个问题只发生在headless
模式中。
- 更新 *
在网站分析期间,我还需要考虑 iframe(仅顶级),因此我还添加了一个逻辑,将驱动程序上下文切换到主页中的每个 iframe 并提取相关 html。
这是应用程序的简化版本:
import traceback
from time import sleep
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
width = 1024
height = 768
chrome_options = Options()
chrome_options.page_load_strategy = 'normal'
chrome_options.add_argument('--enable-automation')
chrome_options.add_argument('disable-infobars')
chrome_options.add_argument('--disable-gpu')
chrome_options.add_argument('--no-sandbox')
chrome_options.add_argument('--lang=en')
chrome_options.add_argument('--ignore-certificate-errors')
chrome_options.add_argument('--allow-insecure-localhost')
chrome_options.add_argument('--allow-running-insecure-content')
chrome_options.add_argument('--disable-notifications')
chrome_options.add_argument('--disable-dev-shm-usage')
chrome_options.add_argument('--disable-browser-side-navigation')
chrome_options.add_argument('--mute-audio')
chrome_options.add_argument('--headless')
chrome_options.add_argument('--force-device-scale-factor=1')
chrome_options.add_argument(f'window-size={width}x{height}')
chrome_options.add_experimental_option(
'prefs', {
'intl.accept_languages': 'en,en_US',
'download.prompt_for_download': False,
'download.default_directory': '/dev/null',
'automatic_downloads': 2,
'download_restrictions': 3,
'notifications': 2,
'media_stream': 2,
'media_stream_mic': 2,
'media_stream_camera': 2,
'durable_storage': 2,
}
)
driver = webdriver.Chrome(options=options)
driver.set_page_load_timeout(10) # Timeout 10 seconds
# Polling queue
while True:
url = queue.pop()
# Try open url
try:
driver.get(url)
except BaseException as e:
print(e)
print(traceback.format_exc())
continue
# Take website screenshot
png = driver.get_screenshot_as_png()
# Extract html from iframes (if any)
htmls = [driver.page_source]
iframes = driver.find_elements_by_xpath("//iframe")
for index, iframe in enumerate(iframes):
try:
driver.switch_to.frame(index)
htmls.append(driver.page_source)
driver.switch_to.default_content()
except BaseException as e:
print(e)
print(traceback.format_exc())
continue
# Do some analysis
for html in htmls:
# ...
pass
# Wait a bit
sleep(0.1)
这是堆栈跟踪的示例:
Opening https://www.yourmechanic.com/user/appointment/3732777/?access_token=HLZYIg&ukey=6quWpg1724633&rcode=abttgi&utm_medium=sms&utm_source= rb
LOAD EXCEPTION Message: timeout: Timed out receiving message from renderer: 10.000
(Session info: headless chrome=83.0.4103.116)
Traceback (most recent call last):
File "/Users/macbmacbookpro4ookpro4/Documents/Projects/python/proj001/main.py", line 202, in inference
driver.get(url)
File "/opt/anaconda3/envs/cv/lib/python3.7/site-packages/selenium/webdriver/remote/webdriver.py", line 333, in get
self.execute(Command.GET, {'url': url})
File "/opt/anaconda3/envs/cv/lib/python3.7/site-packages/selenium/webdriver/remote/webdriver.py", line 321, in execute
self.error_handler.check_response(response)
File "/opt/anaconda3/envs/cv/lib/python3.7/site-packages/selenium/webdriver/remote/errorhandler.py", line 242, in check_response
raise exception_class(message, screen, stacktrace)
selenium.common.exceptions.TimeoutException: Message: timeout: Timed out receiving message from renderer: 10.000
(Session info: headless chrome=83.0.4103.116)
有没有人知道为什么在正确执行一段时间后 Selenium 开始为它尝试打开的任何 url 提供超时异常?
解决方案
此错误消息...
selenium.common.exceptions.TimeoutException: Message: timeout: Timed out receiving message from renderer: 10.000
...意味着ChromeDriver无法与浏览上下文(即Chrome 浏览器会话)进行通信。
深潜
由于多种原因,可能会出现此错误。其中一些原因和补救措施如下:
disable-infobars
并且--enable-automation
几乎是类似的并且disable-infobars
不再被维护。--enable-automation
将服务于您的目的。所以你需要放弃:chrome_options.add_argument('disable-infobars')
您可以在 Chrome v76中的无法隐藏“Chrome 正在由自动化软件控制”信息栏中找到详细讨论
--enable-automation
仍然是 aexperimental_option
所以你需要:chrome_options.add_experimental_option("excludeSwitches", ["enable-automation"])
您可以在如何通过选项在 Selenium IDE 中使用 FirefoxDriver 使用 setExperimentalOption 中找到详细讨论?
如果您打算使用
--enable-automation
,您还需要使用useAutomationExtension
:chrome_options.add_experimental_option("excludeSwitches", ["enable-automation"]) chrome_options.add_experimental_option('useAutomationExtension', False)
--disable-gpu
不再需要,因此您需要删除:chrome_options.add_argument('--disable-gpu')
您可以在 Python Selenium中的 Chrome 选项中找到详细讨论:禁用 GPU 与无头
您可以通过例如选择使用更大的视口
{width}x{height}
1920, 1080
chrome_options.add_argument("window-size=1920,1080")
要启动google-chrome-headless而不是
chrome_options.add_argument('--headless')
您需要使用以下headless
属性:chrome_options.headless = True
您可以在如何配置 ChromeDriver 以通过 Selenium 以 Headless 模式启动 Chrome 浏览器中找到详细讨论?
你可以在Expected condition failed: waiting for element to be clickable for element contains style="display: none;"中找到详细讨论</a>
最后,要切换到一个框架,您需要诱导WebDriverWait为所需
frame to be available and switch to it()
,如下所示:WebDriverWait(driver, 30).until(EC.frame_to_be_available_and_switch_to_it((By.CSS_SELECTOR,"iframe#whovaIframeSpeaker")))
您可以在以下位置找到一些相关的讨论:
参考
您可以在以下位置找到一些有关超时从渲染器接收消息的相关详细讨论:
推荐阅读
- javascript - 为什么单击 iframe 上的 x 时无法暂停视频
- javascript - 删除 b Javascript 中存在的 a 中的元素
- notepad++ - 如何在 Notepad++ 中的 HTML 属性名称后自动插入等号 (=) 和双引号 ("")?
- python - 将 1H 蜡烛数据的 pandas 数据帧重采样为 4H
- database - Odoo - 如何使用 OpenUpgrade 将数据库从 Odoo 12 迁移到 14
- javascript - 将特定键的数据从 javascript 传递给 vue
- python - 在 Python 中使用 super() 进行干燥
- swiftui - 如何在 SwiftUI 中触发状态更改/重绘切换更改
- regex - 无法理解 Perl 正则表达式替换行为
- dart - dart 从嵌套对象数组中抓取字符串