Selenium работает на AWS EC2, но не на AWS Lambda.
Я просмотрел и пробовал почти все сообщения по этой теме, но безуспешно.
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: приведенный ниже ответ не решил проблему.
Ответы
Это сообщение об ошибке ...
"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
Наконец-то я смог заставить его работать
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 года и позже.