Selenium работает на AWS EC2, но не на AWS Lambda.

Nov 16 2020

Я просмотрел и пробовал почти все сообщения по этой теме, но безуспешно.

EC2

Я использую, python 3.6поэтому я использую следующий AMI amzn-ami-hvm-2018.03.0.20181129-x86_64-gp2(см. Здесь ). Как только я подключусь к своему EC2 по SSH, я загружаю Chrome с помощью:

sudo curl https://intoli.com/install-google-chrome.sh | bash
cp -r /opt/google/chrome/ /home/ec2-user/
google-chrome-stable --version
# Google Chrome 86.0.4240.198 

И загрузите и распакуйте соответствующий Chromedriver:

sudo wget https://chromedriver.storage.googleapis.com/86.0.4240.22/chromedriver_linux64.zip
sudo unzip chromedriver_linux64.zip

Устанавливаю python36и seleniumс:

sudo yum install python36 -y
sudo /usr/bin/pip-3.6 install selenium

Затем запустите скрипт:

import os
import selenium
from selenium import webdriver

CURR_PATH = os.getcwd()
chrome_options = webdriver.ChromeOptions()
chrome_options.add_argument('--no-sandbox')
chrome_options.add_argument('--headless')
chrome_options.add_argument('--window-size=1280x1696')
chrome_options.add_argument('--disable-gpu')
chrome_options.add_argument('--disable-dev-shm-usage')
chrome_options.add_argument('--hide-scrollbars')
chrome_options.add_argument('--enable-logging')
chrome_options.add_argument('--log-level=0')
chrome_options.add_argument('--v=99')
chrome_options.add_argument('--single-process')
chrome_options.add_argument('--ignore-certificate-errors')
chrome_options.add_argument('--remote-debugging-port=9222')
chrome_options.binary_location = f"{CURR_PATH}/chrome/google-chrome"
driver = webdriver.Chrome(
    executable_path = f"{CURR_PATH}/chromedriver",
    chrome_options=chrome_options
)
driver.get("https://www.google.com/")
html = driver.page_source
print(html)

Это работает

Лямбда

Затем я заархивирую свои файлы chromedriver и Chrome:

mkdir tmp
mv chromedriver tmp
mv chrome tmp
cd tmp
zip -r9 ../chrome.zip chromedriver chrome

И скопируйте заархивированный файл в S3корзину

Это моя лямбда-функция:

import os
import boto3
from botocore.exceptions import ClientError
import zipfile
import selenium
from selenium import webdriver

s3 = boto3.resource('s3')

def handler(event, context):
    chrome_bucket = os.environ.get('CHROME_S3_BUCKET')
    chrome_key = os.environ.get('CHROME_S3_KEY')
    # DOWNLOAD HEADLESS CHROME FROM S3
    try:    
        # with open('/tmp/headless_chrome.zip', 'wb') as data:
        s3.meta.client.download_file(chrome_bucket, chrome_key, '/tmp/chrome.zip')
        print(os.listdir('/tmp'))
    except ClientError as e:
        raise e
    # UNZIP HEADLESS CHROME
    try:
        with zipfile.ZipFile('/tmp/chrome.zip', 'r') as zip_ref:
            zip_ref.extractall('/tmp')
        # FREE UP SPACE
        os.remove('/tmp/chrome.zip')
        print(os.listdir('/tmp'))
    except:
        raise ValueError('Problem with unzipping Chrome executable')
    # CHANGE PERMISSION OF CHROME
    try:
        os.chmod('/tmp/chromedriver', 0o775)
        os.chmod('/tmp/chrome/chrome', 0o775)
        os.chmod('/tmp/chrome/google-chrome', 0o775)
    except:
        raise ValueError('Problem with changing permissions to Chrome executable')
    # GET LINKS
    chrome_options = webdriver.ChromeOptions()
    chrome_options.add_argument('--no-sandbox')
    chrome_options.add_argument('--headless')
    chrome_options.add_argument('--window-size=1280x1696')
    chrome_options.add_argument('--disable-gpu')
    chrome_options.add_argument('--disable-dev-shm-usage')
    chrome_options.add_argument('--hide-scrollbars')
    chrome_options.add_argument('--enable-logging')
    chrome_options.add_argument('--log-level=0')
    chrome_options.add_argument('--v=99')
    chrome_options.add_argument('--single-process')
    chrome_options.add_argument('--ignore-certificate-errors')
    chrome_options.add_argument('--remote-debugging-port=9222')
    chrome_options.binary_location = "/tmp/chrome/google-chrome"
    driver = webdriver.Chrome(
        executable_path = "/tmp/chromedriver",
        chrome_options=chrome_options
    )
    driver.get("https://www.google.com/")
    html = driver.page_source
    print(html)

Я вижу свои распакованные файлы в /tmpпути.

И моя ошибка:

{
  "errorMessage": "Message: unknown error: unable to discover open pages\n",
  "errorType": "WebDriverException",
  "stackTrace": [
    [
      "/var/task/lib/observer.py",
      69,
      "handler",
      "chrome_options=chrome_options"
    ],
    [
      "/var/task/selenium/webdriver/chrome/webdriver.py",
      81,
      "__init__",
      "desired_capabilities=desired_capabilities)"
    ],
    [
      "/var/task/selenium/webdriver/remote/webdriver.py",
      157,
      "__init__",
      "self.start_session(capabilities, browser_profile)"
    ],
    [
      "/var/task/selenium/webdriver/remote/webdriver.py",
      252,
      "start_session",
      "response = self.execute(Command.NEW_SESSION, parameters)"
    ],
    [
      "/var/task/selenium/webdriver/remote/webdriver.py",
      321,
      "execute",
      "self.error_handler.check_response(response)"
    ],
    [
      "/var/task/selenium/webdriver/remote/errorhandler.py",
      242,
      "check_response",
      "raise exception_class(message, screen, stacktrace)"
    ]
  ]
}

РЕДАКТИРОВАТЬ: Я готов попробовать что угодно на данном этапе. Различные версии Chrome или Chromium, Chromedriver, Python или Selenium.

EDIT2: приведенный ниже ответ не решил проблему.

Ответы

5 DebanjanB Nov 18 2020 at 21:13

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

"errorMessage": "Message: unknown error: unable to discover open pages\n",
"errorType": "WebDriverException"

... означает, что ChromeDriver не смог инициировать / создать новый контекст просмотра, то есть сеанс браузера Chrome .

Кажется , что проблема с ChromeDriver , с функцией защиты от песочниц .


Правило большого пальца

Частая причина сбоя Chrome при запуске - запуск Chrome от имени rootпользователя ( administrator) в Linux. Хотя эту проблему можно обойти, передав --no-sandboxфлаг при создании сеанса WebDriver, такая конфигурация не поддерживается и настоятельно не рекомендуется. Вам необходимо настроить среду для запуска Chrome от имени обычного пользователя.


Детали

Более подробная информация о вашем сценарии использования помогла бы нам лучше проанализировать использование аргументов, которые вы использовали, и первопричину ошибки. Однако несколько мыслей:

  • Что такое песочница? : Песочница - это библиотека C ++, которая позволяет создавать изолированные процессы - процессы, которые выполняются в очень ограниченной среде. Единственные ресурсы, которые процессы изолированной программной среды могут свободно использовать, - это циклы ЦП и память. Например, процессы песочницы не могут записывать на диск или отображать собственные окна. То, что именно они могут делать, контролируется явной политикой. Обработчики хрома - это изолированные процессы.
  • От чего он защищает, а от чего не защищает? : Песочница ограничивает серьезность ошибок в коде, выполняемом внутри песочницы. Такие ошибки не могут установить постоянное вредоносное ПО в учетную запись пользователя (поскольку запись в файловую систему запрещена). Такие ошибки также не могут читать и красть произвольные файлы с машины пользователя. (В Chromium процессы рендеринга изолированы и имеют эту защиту. После удаления NPAPI все остальные плагины также помещаются в песочницу. Также обратите внимание, что процессы рендеринга Chromium изолированы от системы, но еще не из Интернета. Таким образом, доменные изоляция данных пока не предусмотрена.). Песочница не может обеспечить защиту от ошибок в системных компонентах, таких как ядро, на котором она работает.
  • Так как же изолированный процесс, такой как средство визуализации, может чего-либо достичь? : Определенные каналы связи явно открыты для изолированных процессов; процессы могут писать и читать из этих каналов. Более привилегированный процесс может использовать эти каналы для выполнения определенных действий от имени изолированного процесса. В Chromium привилегированным процессом обычно является процесс браузера.

Так что вам, возможно, придется отказаться от этой --no-sandboxопции. Вот ссылка на историю песочницы .


Дополнительные соображения

Еще несколько соображений:

  • При использовании --headlessопции вы не сможете использовать --window-size=1280x1696из-за определенных ограничений.

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

  • Полноэкранный режим в Headless Chrome с использованием Selenium
  • Невозможно развернуть окно Chrome в режиме без головы
  • Аргументом --disable-gpuбыло включение google-chrome-headless на платформе Windows . Это было необходимо, поскольку ранее SwiftShader не выполнял утверждение в Windows в безголовом режиме . Эта проблема была решена с помощью Headless: сделать флаг --disable-gpu ненужным

Вы можете найти соответствующее подробное обсуждение в ERROR: gpu_process_transport_factory.cc (1007) -Lost UI shared context: при инициализации браузера Chrome через ChromeDriver в режиме Headless

  • В дальнейшем вы не упомянули о каких - либо требований для конкретного использования --disable-dev-shm-usage, --hide-scrollbars, --enable-logging, --log-level=0, --v=99, --single-processи --remote-debugging-port=9222аргументы , которые вы решили отказаться от до поры до времени и добавить их обратно в соответствии с вашей спецификацией испытаний .

Рекомендации

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

  • selenium.common.exceptions.WebDriverException: сообщение: неизвестная ошибка: невозможно обнаружить открытые страницы с помощью ChromeDriver через Selenium
  • WebDriverException: неизвестная ошибка: невозможно обнаружить ошибку открытых страниц с ChromeDriver 80.0.3987.106 и Chrome 80.0.3987.122
CPak Dec 13 2020 at 20:28

Наконец-то я смог заставить его работать

Python 3.7
selenium==3.14.0
headless-chromium v1.0.0-55
chromedriver 2.43

Безголовый-Хром

https://github.com/adieuadieu/serverless-chrome/releases/download/v1.0.0-55/stable-headless-chromium-amazonlinux-2017-03.zip

Хромированная отвертка

https://chromedriver.storage.googleapis.com/2.43/chromedriver_linux64.zip

Я добавил хром без головы и хромированную отвертку в Lambda Layer

Разрешения 755на обе работы

Лямбда

Лямбда-функция выглядит так

import os
import selenium
from selenium import webdriver


def handler(event, context):
    print(os.listdir('/opt'))
    # 
    chrome_options = webdriver.ChromeOptions()
    chrome_options.add_argument('--no-sandbox')
    chrome_options.add_argument('--headless')
    chrome_options.add_argument('--single-process')
    chrome_options.add_argument('--disable-dev-shm-usage')
    chrome_options.binary_location = f"/opt/headless-chromium"
    driver = webdriver.Chrome(
        executable_path = f"/opt/chromedriver",
        chrome_options=chrome_options
    )
    driver.get("https://www.google.com/")
    html = driver.page_source
    driver.close()
    driver.quit()
    print(html)

Надеюсь, это поможет кому-то в четвертом квартале 2020 года и позже.