Selenium funziona su AWS EC2 ma non su AWS Lambda
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
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
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.