Selenium funziona su AWS EC2 ma non su AWS Lambda

Nov 16 2020

Ho guardato e provato quasi tutti gli altri post su questo argomento senza fortuna.

EC2

Sto usando python 3.6quindi sto usando la seguente AMI amzn-ami-hvm-2018.03.0.20181129-x86_64-gp2(vedi qui ). Una volta effettuato l'accesso SSH al mio EC2, scarico Chrome con:

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 

E scarica e decomprimi il Chromedriver corrispondente:

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

Installo python36e seleniumcon:

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

Quindi esegui lo script:

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)

Funziona

Lambda

Quindi comprimo i miei file Chromedriver e Chrome:

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

E copia il file zippato in un S3bucket

Questa è la mia funzione lambda:

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)

Sono in grado di vedere i miei file decompressi nel /tmppercorso.

E il mio errore:

{
  "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: sono disposto a provare qualsiasi cosa a questo punto. Diverse versioni di Chrome o Chromium, Chromedriver, Python o Selenium.

EDIT2: la risposta di seguito non ha risolto il problema.

Risposte

5 DebanjanB Nov 18 2020 at 21:13

Questo messaggio di errore ...

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

... implica che ChromeDriver non è stato in grado di avviare / generare un nuovo contesto di navigazione, ad esempio la sessione del browser Chrome .

Sembra che il problema sia con ChromeDriver , la funzione di sicurezza di Sandboxing .


Regola del pollice

Una causa comune dell'arresto anomalo di Chrome durante l'avvio è l'esecuzione di Chrome come rootutente ( administrator) su Linux. Sebbene sia possibile aggirare questo problema passando il --no-sandboxflag durante la creazione della sessione WebDriver, tale configurazione non è supportata e altamente sconsigliata. Devi invece configurare il tuo ambiente per eseguire Chrome come un utente normale.


Dettagli

Qualche dettaglio in più sul tuo caso d'uso ci avrebbe aiutato ad analizzare meglio l'utilizzo degli argomenti che hai usato e la causa principale dell'errore. Tuttavia, alcuni pensieri:

  • Cos'è la sandbox? : La sandbox è una libreria C ++ che consente la creazione di processi in modalità sandbox, processi che vengono eseguiti in un ambiente molto restrittivo. Le uniche risorse che i processi in modalità sandbox possono utilizzare liberamente sono i cicli della CPU e la memoria. Ad esempio, i processi sandbox non possono scrivere su disco o visualizzare le proprie finestre. Quello che possono fare esattamente è controllato da una politica esplicita. I renderer di Chromium sono processi in modalità sandbox.
  • Da cosa protegge e non protegge? : La sandbox limita la gravità dei bug nel codice in esecuzione all'interno della sandbox. Tali bug non possono installare malware persistente nell'account dell'utente (perché la scrittura sul filesystem è vietata). Tali bug inoltre non possono leggere e rubare file arbitrari dalla macchina dell'utente. In Chromium, i processi di rendering sono in modalità sandbox e hanno questa protezione. Dopo la rimozione di NPAPI, anche tutti i plug-in rimanenti vengono sottoposti a sandbox. Tieni presente che i processi di rendering di Chromium sono isolati dal sistema, ma non ancora dal Web. Pertanto l'isolamento dei dati non è ancora fornito.). La sandbox non può fornire alcuna protezione contro i bug nei componenti di sistema come il kernel su cui è in esecuzione.
  • Quindi come può un processo sandbox come un renderer realizzare qualcosa? : Alcuni canali di comunicazione sono esplicitamente aperti per i processi in modalità sandbox; i processi possono scrivere e leggere da questi canali. Un processo più privilegiato può utilizzare questi canali per eseguire determinate azioni per conto del processo in modalità sandbox. In Chromium, il processo privilegiato è solitamente il processo del browser.

Quindi potrebbe essere necessario eliminare l' --no-sandboxopzione. Ecco il link alla storia di Sandbox .


Considerazioni aggiuntive

Altre considerazioni:

  • Durante l'utilizzo --headlessdell'opzione non sarai in grado di utilizzare a --window-size=1280x1696causa di determinati vincoli.

Puoi trovare un paio di discussioni dettagliate pertinenti in:

  • Schermo intero in Headless Chrome utilizzando Selenium
  • Non in grado di massimizzare la finestra di Chrome in modalità headless
  • L'argomento --disable-gpuera quello di abilitare google-chrome-headless sulla piattaforma Windows . Era necessario poiché SwiftShader fallisce un'asserzione su Windows in modalità headless in precedenza. Questo problema è stato risolto tramite Headless: rendere il flag --disable-gpu non necessario

Puoi trovare una discussione dettagliata pertinente in ERRORE: gpu_process_transport_factory.cc (1007) - Contesto condiviso dell'interfaccia utente persa: durante l'inizializzazione del browser Chrome tramite ChromeDriver in modalità Headless

  • Inoltre non è stato menzionato ogni specifica esigenza di utilizzare --disable-dev-shm-usage, --hide-scrollbars, --enable-logging, --log-level=0, --v=99, --single-processe --remote-debugging-port=9222argomenti che si sceglie di abbandonare per il momento e aggiungerle di nuovo secondo la vostra prova specifica .

Riferimenti

Puoi trovare un paio di discussioni dettagliate pertinenti in:

  • selenium.common.exceptions.WebDriverException: Messaggio: errore sconosciuto: impossibile trovare pagine aperte utilizzando ChromeDriver tramite Selenium
  • WebDriverException: errore sconosciuto: impossibile scoprire l'errore di pagine aperte con ChromeDriver 80.0.3987.106 e Chrome 80.0.3987.122
CPak Dec 13 2020 at 20:28

Finalmente sono riuscito a farlo funzionare

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

Headless-Chromium

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

Ho aggiunto cromo senza testa e fiume cromato a un Lambda Layer

Autorizzazioni 755per entrambe le opere

Lambda

La funzione Lambda ha questo aspetto

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)

Spero che questo aiuti qualcuno nel quarto trimestre del 2020 e dopo.