Selenium выдает «Истекло время получения сообщения от средства визуализации» для всех веб-сайтов после некоторого времени выполнения. - PullRequest
0 голосов
/ 14 июля 2020

У меня есть приложение, в котором мне нужен долго работающий экземпляр веб-драйвера Selenium (я использую Chrome драйвер 83.0.4103.39 в безголовом режиме). По сути, приложение постоянно извлекает URL-данные из очереди и передает извлеченный URL-адрес Selenium, который должен выполнить некоторый анализ на веб-сайте. Многие из этих веб-сайтов могут быть недоступны, недоступны или сломаны, поэтому я установил тайм-аут загрузки страницы в 10 секунд, чтобы Selenium не ждал бесконечно загрузки страницы.
Проблема, с которой я столкнулся, заключается в том, что после некоторого времени выполнения (скажем, 10 минут) Selenium начинает выдавать ошибку Timed out receiving message from renderer для каждого URL-адреса. Первоначально он работает правильно, он правильно открывает хорошие веб-сайты и уходит по таймауту на плохие (сайт не загружается), но через некоторое время он начинает давать таймаут для всего, даже для сайтов, которые должны открываться правильно (я проверил, они корректно открываются в браузере Chrome). Мне сложно отладить эту проблему, так как каждое исключение в приложении отлавливается правильно. Я также заметил, что эта проблема возникает только в режиме headless.

  • UPDATE *
    Во время анализа веб-сайта мне также нужно учитывать iframe (только верхний уровень), поэтому я также добавил лог c для переключения контекста драйвера на каждый 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-адреса, который он пытается открыть?

1 Ответ

1 голос
/ 14 июля 2020

Это сообщение об ошибке ...

selenium.common.exceptions.TimeoutException: Message: timeout: Timed out receiving message from renderer: 10.000

... означает, что ChromeDriver не смог связаться с Контекстом просмотра т.е. Chrome Браузер сеанс.

Deep Dive

Эта ошибка может возникнуть по нескольким причинам. Пара этих причин и средство устранения таковы:

  • disable-infobars и --enable-automation почти аналогичны и disable-infobars больше не поддерживается. --enable-automation послужит вашей цели. Таким образом, вам нужно отбросить:

    chrome_options.add_argument('disable-infobars')
    

Подробное обсуждение Невозможно скрыть «Chrome контролируется автоматизированным программным обеспечением» на информационной панели Chrome v76

  • --enable-automation по-прежнему experimental_option, поэтому вам нужно:

    chrome_options.add_experimental_option("excludeSwitches", ["enable-automation"])
    

Вы можете найти подробное обсуждение в Как я могу использовать setExperimentalOption через Параметры с помощью FirefoxDriver в Selenium IDE?

  • Если вы собираетесь использовать --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')
    

Вы можете найти подробное обсуждение в Chrome Параметры в Python Selenium: Disable GPU vs Headless

  • Вы можете выбрать более крупное Окно просмотра - {width}x{height}, например, 1920, 1080

    chrome_options.add_argument("window-size=1920,1080")
    

Подробное обсуждение можно найти в Как установить размер окна в Seleni um Chrome Python

  • Чтобы запустить вместо chrome_options.add_argument('--headless'), вам нужно использовать headless следующим образом:

    chrome_options.headless = True
    

Вы можете найти подробное обсуждение в Как настроить ChromeDriver для запуска браузера Chrome в режиме Headless через Selenium?

  • Поскольку у вас есть перечисленные все элементы , стоит упомянуть, что вы не можете switch_to все <iframe> / <frame>, так как некоторые из них могут иметь значение атрибута style , установленное как display: none;.

Вы можете найти подробное обсуждение в Ожидаемое условие не выполнено: ожидание кликабельного элемента для элемента, содержащего 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")))
    

Вы можете найти пару соответствующих обсуждений в:

Ссылки

Вы можете найти пару соответствующих подробных обсуждений на Истекло время получения сообщения от средства визуализации в:

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...