Selenium berfungsi di AWS EC2 tetapi tidak di AWS Lambda
Saya telah melihat dan mencoba hampir setiap posting lain tentang topik ini tanpa hasil.
EC2
Saya menggunakan python 3.6jadi saya menggunakan AMI berikut amzn-ami-hvm-2018.03.0.20181129-x86_64-gp2(lihat di sini ). Setelah saya SSH ke EC2 saya, saya mengunduh Chrome dengan:
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
Dan unduh serta unzip Chromedriver yang cocok:
sudo wget https://chromedriver.storage.googleapis.com/86.0.4240.22/chromedriver_linux64.zip
sudo unzip chromedriver_linux64.zip
Saya menginstal python36dan seleniumdengan:
sudo yum install python36 -y
sudo /usr/bin/pip-3.6 install selenium
Kemudian jalankan skrip:
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)
Ini bekerja
Lambda
Saya kemudian membuat zip file chromedriver dan Chrome saya:
mkdir tmp
mv chromedriver tmp
mv chrome tmp
cd tmp
zip -r9 ../chrome.zip chromedriver chrome
Dan salin file zip tersebut ke S3ember
Ini adalah fungsi lambda saya:
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)
Saya dapat melihat file saya yang telah dibuka zipnya di /tmpjalur.
Dan kesalahan saya:
{
"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: Saya ingin mencoba apa pun saat ini. Versi berbeda dari Chrome atau Chromium, Chromedriver, Python atau Selenium.
EDIT2: Jawaban di bawah ini tidak menyelesaikan masalah.
Jawaban
Pesan kesalahan ini ...
"errorMessage": "Message: unknown error: unable to discover open pages\n",
"errorType": "WebDriverException"
... menyiratkan bahwa ChromeDriver tidak dapat memulai / menelurkan Konteks Penjelajahan baru, yaitu sesi Browser Chrome .
Tampaknya masalah ini dengan ChromeDriver , s fitur keamanan dari sandboxing .
Aturan jempol
Penyebab umum Chrome mogok saat memulai adalah menjalankan Chrome sebagai
rootpengguna (administrator) di Linux. Meskipun mungkin untuk mengatasi masalah ini dengan meneruskan--no-sandboxtanda saat membuat sesi WebDriver Anda, konfigurasi seperti itu tidak didukung dan sangat tidak disarankan. Anda perlu mengonfigurasi lingkungan Anda untuk menjalankan Chrome sebagai pengguna biasa.
Detail
Sedikit lebih banyak detail tentang kasus penggunaan Anda akan membantu kami menganalisis penggunaan argumen yang telah Anda gunakan dan akar penyebab kesalahan dengan cara yang lebih baik. Namun, beberapa pemikiran:
- Apa itu kotak pasir? : Sandbox adalah pustaka C ++ yang memungkinkan pembuatan proses sandbox - proses yang dijalankan dalam lingkungan yang sangat terbatas. Satu-satunya sumber daya yang dapat digunakan dengan bebas proses sandbox adalah siklus CPU dan memori. Misalnya, proses kotak pasir tidak dapat menulis ke disk atau menampilkan jendelanya sendiri. Apa sebenarnya yang dapat mereka lakukan dikendalikan oleh kebijakan eksplisit. Perender Chromium adalah proses kotak pasir.
- Apa dan tidak melindunginya? : Kotak pasir membatasi tingkat keparahan bug dalam kode yang berjalan di dalam kotak pasir. Bug semacam itu tidak dapat menginstal malware persisten di akun pengguna (karena menulis ke sistem file dilarang). Bug semacam itu juga tidak dapat membaca dan mencuri file sewenang-wenang dari mesin pengguna. (Di Chromium, proses perender dalam kotak pasir dan memiliki perlindungan ini. Setelah NPAPI dihapus, semua plugin yang tersisa juga dimasukkan ke dalam kotak pasir. Perhatikan juga bahwa proses perender Chromium diisolasi dari sistem, tetapi belum dari web. Oleh karena itu, berbasis domain isolasi data belum tersedia.). Sandbox tidak dapat memberikan perlindungan apa pun terhadap bug dalam komponen sistem seperti kernel tempat ia dijalankan.
- Jadi bagaimana proses kotak pasir seperti perender mencapai sesuatu? : Saluran komunikasi tertentu secara eksplisit terbuka untuk proses kotak pasir; proses dapat menulis dan membaca dari saluran ini. Proses yang lebih istimewa dapat menggunakan saluran ini untuk melakukan tindakan tertentu atas nama proses dalam kotak pasir. Di Chromium, proses yang diistimewakan biasanya proses browser.
Jadi, Anda mungkin perlu membatalkan --no-sandboxopsi. Berikut ini tautan ke cerita Kotak Pasir .
Pertimbangan Tambahan
Beberapa pertimbangan lagi:
- Saat menggunakan
--headlessopsi, Anda tidak akan dapat menggunakan--window-size=1280x1696karena kendala tertentu.
Anda dapat menemukan beberapa pembahasan rinci yang relevan di:
- Layar penuh di Headless Chrome menggunakan Selenium
- Tidak dapat memaksimalkan Jendela Chrome dalam mode tanpa kepala
- Argumennya
--disable-gpuadalah untuk mengaktifkan google-chrome-headless pada platform windows . Itu diperlukan karena SwiftShader gagal menegaskan pada Windows dalam mode tanpa kepala sebelumnya. Masalah ini telah diatasi melalui Headless: make --disable-gpu flag tidak perlu
Anda dapat menemukan diskusi mendetail yang relevan di ERROR: gpu_process_transport_factory.cc (1007) -Lost UI berbagi konteks: saat menginisialisasi browser Chrome melalui ChromeDriver dalam mode Headless
- Selanjutnya Anda belum disebutkan persyaratan tertentu menggunakan
--disable-dev-shm-usage,--hide-scrollbars,--enable-logging,--log-level=0,--v=99,--single-processdan--remote-debugging-port=9222argumen yang Anda memilih untuk menjatuhkan untuk saat ini dan menambahkan mereka kembali sebagai per Anda Uji Spesifikasi .
Referensi
Anda dapat menemukan beberapa pembahasan rinci yang relevan di:
- selenium.common.exceptions.WebDriverException: Pesan: kesalahan tidak diketahui: tidak dapat menemukan halaman yang terbuka menggunakan ChromeDriver melalui Selenium
- WebDriverException: kesalahan tidak diketahui: tidak dapat menemukan kesalahan halaman terbuka dengan ChromeDriver 80.0.3987.106 dan Chrome 80.0.3987.122
Saya akhirnya bisa membuatnya bekerja
Python 3.7
selenium==3.14.0
headless-chromium v1.0.0-55
chromedriver 2.43
Tanpa Kepala-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
Saya menambahkan headless-chromium dan chromedriver ke a Lambda Layer
Izin 755untuk keduanya bekerja
Lambda
Fungsi Lambda terlihat seperti ini
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)
Semoga ini bisa membantu seseorang di Q4 2020 dan setelahnya.