当前位置: 首页 > 知识库问答 >
问题:

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

卢普松
2023-03-14

我已经看过并尝试了几乎所有关于这个话题的其他帖子,但运气不好。

我使用的是python 3.6,所以我使用的是以下AMIamzn-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 

下载并解压缩匹配的Chromedriver:

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

我安装了python36selenium

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

然后运行脚本:

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)

这很管用

然后我压缩我的chrome驱动程序和Chrome文件:

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

并将压缩后的文件复制到S3bucket中

这是我的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)

我可以在/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)"
    ]
  ]
}

编辑:在这一点上,我愿意尝试任何东西。不同版本的Chrome或Chromium、铬驱动程序、Python或硒。

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


共有3个答案

白驰
2023-03-14

@CPak的答案对我有效,我只需将无头铬铬驱动程序复制到/tmp并授予权限,其余代码相同:

from shutil import copyfile

def permissions(origin_path, destiny_path):
    copyfile(origin_path, destiny_path)
    os.chmod(destiny_path, 0o775)

    
def lambda_handler(event, context):
    permissions('/opt/chromedriver','/tmp/chromedriver')
    permissions('/opt/headless-chromium','/tmp/headless-chromium')
池照
2023-03-14

我终于能让它工作了

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

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

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

我将无头铬和铬驱动添加到Lambda层

两个作品的权限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)

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

景宏盛
2023-03-14

此错误消息。。。

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

...意味着ChromeDriver无法启动/生成新的浏览上下文,即Chrome浏览器会话。

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

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

更多关于你的usecase的细节可以帮助我们更好地分析你使用的参数的用法和错误的根本原因。然而,有一些想法:

  • 沙箱是什么沙盒是一个C库,允许创建沙盒进程,即在非常严格的环境中执行的进程。沙盒进程可以自由使用的唯一资源是CPU周期和内存。例如,沙盒进程无法写入磁盘或显示自己的窗口。他们能做的具体事情是由明确的政策控制的。铬渲染器是沙盒流程

因此,您可能需要删除--no sandbox选项。下面是沙盒故事的链接。

还有一些考虑:

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

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

  • 使用硒的无头Chrome全屏
  • 在无头模式下无法最大化Chrome窗口
  • 参数--disable-gpu是为了在windows平台上启用google-chrome-Headless。这是因为SwiftShader在之前的无头模式下无法在Windows上断言而需要的。这个问题通过Headless解决了:不需要设置--disable-gpu标志

您可以在错误中找到相关的详细讨论:gpu_进程_传输_工厂。cc(1007)-丢失用户界面共享上下文:在无头模式下通过ChromeDriver初始化Chrome浏览器时

  • 此外,您还没有提到使用--禁用开发shm用法--隐藏滚动条--启用日志记录--日志级别=0--v=99--单进程--远程调试端口=9222参数,您选择暂时删除这些参数,并根据测试规范将它们添加回

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

  • selenium.common.exceptions.WebDriver异常:消息:未知错误:无法通过Selenium使用ChromeDriver发现打开的页面
  • WebDriver异常:未知错误:无法发现打开页面错误与ChromeDriver80.0.3987.106和Chrome80.0.3987.122

 类似资料:
  • 问题内容: 嗨,我只是简单地尝试在www.example.com上获取h1标签,该标签显示为“ Example Domain”。该代码适用于http://www.example.com,但不适用于https://www.exmaple.com。我该如何解决这个问题?谢谢 问题答案: PhantomJSDriver不支持(所有)DesiredCapabilities。 你会需要: 记录在这里:htt

  • 所以我使用这种方法写入文件,它在windows上运行完全正常,但在mac上运行时,它会创建文件,但它们是空的。 我知道数据是正确的,因为它打印正确。感谢您的任何帮助,这真的让我绊倒了。

  • 列名称的类型为int[] 上述查询适用于postgresql,但不适用于hsqldb,甚至适用于sql 尝试的hsqldb版本:2.2.9和2.3.0 在hsqldb中工作的sql是从table_name中选择x,unnest(column_name)y(x)x和y不是该表的列。

  • 我能够成功地打电话给邮递员: /mfp/api/az/v1/token和 /mfpadmin/management-apis/2.0/runtimes/mfp/applications 我正在获取从/mfp/api/az/v1/token接收的承载令牌,并将其添加到/mfp/applications的授权标头中。 我收到了来自两者的200个响应,并从每个API中获取了预期的信息。 然后,我选择从P

  • 我一直在使用声纳3.2 同样的配置,当我升级到SonarQube 4.4时 声纳项目属性: 请帮助整理这些例外 问候, KP

  • 关于redash,我有一个问题。这是请求。在上,它工作得很好。查询示例: 但在axios上,它抛出: 网络错误 并在控制台上写: 访问XMLHttpRequest at