Selenium 适用于 AWS EC2 但不适用于 AWS Lambda

CPa*_*Pak 5 python selenium amazon-web-services selenium-webdriver

我已经查看并尝试了几乎所有关于此主题的其他帖子,但都没有成功。

EC2

我正在使用,python 3.6所以我正在使用以下 AMI amzn-ami-hvm-2018.03.0.20181129-x86_64-gp2(请参阅此处)。通过 SSH 连接到我的 EC2 后,我使用以下命令下载 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 
Run Code Online (Sandbox Code Playgroud)

并下载并解压缩匹配的 Chromedriver:

sudo wget https://chromedriver.storage.googleapis.com/86.0.4240.22/chromedriver_linux64.zip
sudo unzip chromedriver_linux64.zip
Run Code Online (Sandbox Code Playgroud)

我安装python36selenium使用:

sudo yum install python36 -y
sudo /usr/bin/pip-3.6 install selenium
Run Code Online (Sandbox Code Playgroud)

然后运行脚本:

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)
Run Code Online (Sandbox Code Playgroud)

这有效

拉姆达

然后我压缩我的 chromedriver 和 Chrome 文件:

mkdir tmp
mv chromedriver tmp
mv chrome tmp
cd tmp
zip -r9 ../chrome.zip chromedriver chrome
Run Code Online (Sandbox Code Playgroud)

并将压缩文件复制到S3存储桶

这是我的 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)
Run Code Online (Sandbox Code Playgroud)

我可以在/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)"
    ]
  ]
}
Run Code Online (Sandbox Code Playgroud)

编辑:此时我愿意尝试任何事情。不同版本的 Chrome 或 Chromium、Chromedriver、Python 或 Selenium。

EDIT2:下面的答案没有解决问题。

Deb*_*anB 5

这个错误信息...

"errorMessage": "Message: unknown error: unable to discover open pages\n",
"errorType": "WebDriverException"
Run Code Online (Sandbox Code Playgroud)

...暗示ChromeDriver无法启动/生成新的浏览上下文,Chrome 浏览器会话。

问题似乎出在 ChromeDriver沙盒安全功能上。


经验法则

Chrome 在启动期间崩溃的一个常见原因是在 Linux 上以root用户 ( administrator)运行 Chrome 。虽然可以通过--no-sandbox在创建 WebDriver 会话时传递标志来解决此问题,但这种配置不受支持且非常不鼓励。您需要将环境配置为以普通用户身份运行 Chrome。


细节

有关您的用例的更多详细信息将帮助我们以更好的方式分析您使用的参数的用法以及错误的根本原因。不过,有几点想法:

  • 什么是沙箱?:沙箱是一个 C++ 库,它允许创建沙箱进程——在非常严格的环境中执行的进程。沙盒进程可以自由使用的唯一资源是 CPU 周期和内存。例如,沙箱进程不能写入磁盘或显示它们自己的窗口。他们究竟能做什么是由明确的政策控制的。Chromium 渲染器是沙盒进程。
  • 它保护什么,不保护什么?:沙箱限制了在沙箱内运行的代码中错误的严重性。此类错误无法在用户帐户中安装持久性恶意软件(因为禁止写入文件系统)。此类漏洞也无法从用户机器上读取和窃取任意文件。(在 Chromium 中,渲染器进程被沙盒化并具有此保护。在 NPAPI 移除后,所有剩余的插件也被沙盒化。另请注意,Chromium 渲染器进程与系统隔离,但尚未与 Web 隔离。因此,基于域的尚未提供数据隔离。)。沙箱无法针对系统组件(例如运行它的内核)中的错误提供任何保护。
  • 那么像渲染器这样的沙盒进程是如何完成任何事情的呢?:某些通信渠道是明确为沙盒进程开放的;进程可以从这些通道写入和读取。更高特权的进程可以使用这些通道代表沙盒进程执行某些操作。在 Chromium 中,特权进程通常是浏览器进程。

所以你可能需要放弃这个--no-sandbox选项。这是沙盒故事的链接。


其他注意事项

还有一些考虑:

  • 使用--headless选项时,--window-size=1280x1696由于某些限制,您将无法使用。

您可以在以下位置找到一些相关的详细讨论:

您可以在ERROR:gpu_process_transport_factory.cc(1007)-Lost UI shared context 中找到相关的详细讨论:在 Headless 模式下通过 ChromeDriver 初始化 Chrome 浏览器时

  • 另外你还没有提到任何具体的要求使用--disable-dev-shm-usage--hide-scrollbars--enable-logging--log-level=0--v=99--single-process--remote-debugging-port=9222你选择放弃暂时并将它们添加回,按您的参数测试规范

参考

您可以在以下位置找到一些相关的详细讨论:


CPa*_*Pak 2

我终于能够让它工作了

Python 3.7
selenium==3.14.0
headless-chromium v1.0.0-55
chromedriver 2.43
Run Code Online (Sandbox Code Playgroud)

无头铬

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

Chrome驱动程序

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

我将 headless-chromium 和 chromedriver 添加到Lambda Layer

755两部作品的权限

拉姆达

Lambda 函数如下所示

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)
Run Code Online (Sandbox Code Playgroud)

希望这对 2020 年第四季度及之后的人有所帮助。


归档时间:

查看次数:

1350 次

最近记录:

4 年,10 月 前