Selen funktioniert mit AWS EC2, jedoch nicht mit AWS Lambda

Nov 16 2020

Ich habe fast jeden anderen Beitrag zu diesem Thema ohne Glück angeschaut und ausprobiert.

EC2

Ich benutze python 3.6also folgendes AMI amzn-ami-hvm-2018.03.0.20181129-x86_64-gp2(siehe hier ). Sobald ich SSH in mein EC2 habe, lade ich Chrome herunter mit:

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 

Laden Sie den passenden Chromedriver herunter und entpacken Sie ihn:

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

Ich installiere python36und seleniummit:

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

Führen Sie dann das Skript aus:

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)

Das funktioniert

Lambda

Ich komprimiere dann meine Chromedriver- und Chrome-Dateien:

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

Und kopieren Sie die komprimierte Datei in einen S3Bucket

Dies ist meine Lambda-Funktion:

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)

Ich kann meine entpackten Dateien im /tmpPfad sehen.

Und mein Fehler:

{
  "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)"
    ]
  ]
}

EDIT: Ich bin bereit, an dieser Stelle alles auszuprobieren. Verschiedene Versionen von Chrome oder Chromium, Chromedriver, Python oder Selen.

EDIT2: Die Antwort unten hat das Problem nicht gelöst.

Antworten

5 DebanjanB Nov 18 2020 at 21:13

Diese Fehlermeldung ...

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

... bedeutet , dass die ChromeDriver nicht in der Lage war , eine neue zu initiieren / laichen Browsing Context dh Chrome Browser - Sitzung.

Es scheint, dass das Problem bei ChromeDriver liegt , der Sicherheitsfunktion von Sandboxing .


Faustregel

Eine häufige Ursache für einen Absturz von Chrome beim Start ist das Ausführen von Chrome als rootuser ( administrator) unter Linux. Während es möglich ist, dieses Problem zu --no-sandboxumgehen, indem Sie beim Erstellen Ihrer WebDriver-Sitzung das Flag übergeben, wird eine solche Konfiguration nicht unterstützt und dringend empfohlen. Sie müssen Ihre Umgebung so konfigurieren, dass Chrome stattdessen als normaler Benutzer ausgeführt wird.


Einzelheiten

Ein bisschen mehr Details zu Ihrem Anwendungsfall hätten uns geholfen, die Verwendung der von Ihnen verwendeten Argumente und die Grundursache des Fehlers besser zu analysieren. Ein paar Gedanken:

  • Was ist der Sandkasten? : Die Sandbox ist eine C ++ - Bibliothek, mit der Sandbox-Prozesse erstellt werden können - Prozesse, die in einer sehr restriktiven Umgebung ausgeführt werden. Die einzigen Ressourcen, die Sandbox-Prozesse frei nutzen können, sind CPU-Zyklen und Speicher. Beispielsweise können Sandbox-Prozesse nicht auf die Festplatte schreiben oder ihre eigenen Fenster anzeigen. Was genau sie tun können, wird durch eine explizite Richtlinie gesteuert. Chrom-Renderer sind Sandbox-Prozesse.
  • Wovor schützt und schützt es nicht? : Die Sandbox begrenzt die Schwere von Fehlern im Code, der in der Sandbox ausgeführt wird. Solche Fehler können keine dauerhafte Malware im Benutzerkonto installieren (da das Schreiben in das Dateisystem verboten ist). Solche Fehler können auch keine beliebigen Dateien vom Computer des Benutzers lesen und stehlen. (In Chromium sind die Renderer-Prozesse in einer Sandbox gespeichert und verfügen über diesen Schutz. Nach dem Entfernen des NPAPI werden auch alle verbleibenden Plugins in einer Sandbox gespeichert. Beachten Sie außerdem, dass Chromium-Renderer-Prozesse vom System, jedoch noch nicht vom Web isoliert sind. Daher domänenbasiert Datenisolation ist noch nicht vorgesehen.). Die Sandbox kann keinen Schutz gegen Fehler in Systemkomponenten wie dem Kernel bieten, auf dem sie ausgeführt wird.
  • Wie kann ein Sandbox-Prozess wie ein Renderer etwas erreichen? : Bestimmte Kommunikationskanäle sind explizit für Sandbox-Prozesse geöffnet. Die Prozesse können aus diesen Kanälen schreiben und lesen. Ein privilegierterer Prozess kann diese Kanäle verwenden, um bestimmte Aktionen im Namen des Sandbox-Prozesses auszuführen. In Chromium ist der privilegierte Prozess normalerweise der Browserprozess.

Daher müssen Sie möglicherweise die --no-sandboxOption löschen. Hier ist der Link zur Sandbox- Geschichte.


Weitere Überlegungen

Einige weitere Überlegungen:

  • Während Sie die --headlessOption verwenden, können Sie sie --window-size=1280x1696aufgrund bestimmter Einschränkungen nicht verwenden.

Einige relevante ausführliche Diskussionen finden Sie in:

  • Vollbild in Headless Chrome mit Selen
  • Chrome Window kann im Headless-Modus nicht maximiert werden
  • Das Argument --disable-gpuwar, Google-Chrome-Headless auf Windows- Plattform zu aktivieren . Es wurde benötigt, da SwiftShader eine Bestätigung unter Windows im Headless-Modus früher nicht bestanden hat. Dieses Problem wurde durch Headless behoben : Machen Sie das Flag --disable-gpu unnötig

Eine relevante ausführliche Diskussion finden Sie in ERROR: gpu_process_transport_factory.cc (1007) - Verlust des freigegebenen UI-Kontexts: Beim Initialisieren des Chrome-Browsers über ChromeDriver im Headless-Modus

  • Des Weiteren haben Sie keine spezielle Anforderung der Verwendung erwähnt --disable-dev-shm-usage, --hide-scrollbars, --enable-logging, --log-level=0, --v=99, --single-processund --remote-debugging-port=9222Argumente , die Sie sich für die Zeit Wesen und fügen Sie sie zurück nach Ihren Drop Test Specification .

Verweise

Einige relevante ausführliche Diskussionen finden Sie in:

  • selenium.common.exceptions.WebDriverException: Meldung: unbekannter Fehler: Offene Seiten können mit ChromeDriver über Selenium nicht erkannt werden
  • WebDriverException: Unbekannter Fehler: Fehler bei geöffneten Seiten mit ChromeDriver 80.0.3987.106 und Chrome 80.0.3987.122 konnte nicht erkannt werden
CPak Dec 13 2020 at 20:28

Ich konnte es endlich zum Laufen bringen

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

Headless-Chrom

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

Chromedriver

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

Ich habe a Headless-Chrom und Chromedriver hinzugefügt Lambda Layer

Berechtigungen 755für beide Werke

Lambda

Die Lambda-Funktion sieht so aus

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)

Hoffe das hilft jemandem im vierten Quartal 2020 und danach.