AWS Lambda未导入LXML

时间:2016-04-04 07:50:53

标签: python amazon-web-services lxml aws-lambda

我正在尝试在AWS Lambda中使用LXML模块并且没有运气。我使用以下命令下载了LXML:

pip install lxml -t folder

将其下载到我的lambda函数部署包。我将lambda函数的内容压缩为所有其他lambda函数,然后将其上传到AWS Lambda。

然而,无论我尝试什么,我在运行该函数时都会收到此错误:

Unable to import module 'handler': /var/task/lxml/etree.so: undefined symbol: PyFPE_jbuf

当我在本地运行它时,我没有问题,只是当我在Lambda上运行时出现这个问题。

9 个答案:

答案 0 :(得分:6)

我遇到了同样的问题。

Raphaël Braud发布的链接很有帮助,这个链接也是如此: https://nervous.io/python/aws/lambda/2016/02/17/scipy-pandas-lambda/

使用这两个链接,我能够成功导入lxml和其他必需的包。以下是我遵循的步骤:

  • 使用Amazon Linux ami启动ec2计算机
  • 运行以下脚本以累积依赖项:

    set -e -o pipefail
    sudo yum -y upgrade
    sudo yum -y install gcc python-devel libxml2-devel libxslt-devel
    
    virtualenv ~/env && cd ~/env && source bin/activate
    pip install lxml
    for dir in lib64/python2.7/site-packages \
         lib/python2.7/site-packages
    do
    if [ -d $dir ] ; then
       pushd $dir; zip -r ~/deps.zip .; popd
    fi
    done  
    mkdir -p local/lib
    cp /usr/lib64/ #list of required .so files
    local/lib/
    zip -r ~/deps.zip local/lib
    
  • 创建link中指定的处理程序和工作程序文件。示例文件内容:

handler.py

import os
import subprocess


libdir = os.path.join(os.getcwd(), 'local', 'lib')

def handler(event, context):
    command = 'LD_LIBRARY_PATH={} python worker.py '.format(libdir)
    output = subprocess.check_output(command, shell=True)

    print output

    return

worker.py:

import lxml

def sample_function( input_string = None):
    return "lxml import successful!"

if __name__ == "__main__":
    result = sample_function()
    print result
  • 将处理程序和工作程序添加到zip文件。

以下是上述步骤后zip文件的结构:

deps 
├── handler.py
├── worker.py 
├── local
│   └── lib
│       ├── libanl.so
│       ├── libBrokenLocale.so
|       ....
├── lxml
│   ├── builder.py
│   ├── builder.pyc
|       ....
├── <other python packages>
  • 确保在创建lambda函数时指定正确的处理程序名称。在上面的例子中,它将是“handler.handler”

希望这有帮助!

答案 1 :(得分:4)

根据这些答案,我发现以下内容效果很好。

这里的妙语是使用带有静态库的python compile lxml,并安装在当前目录而不是site-packages中。

这也意味着你可以像往常一样编写你的python代码,而不需要一个独特的worker.py或摆弄LD_LIBRARY_PATH

sudo yum groupinstall 'Development Tools'
sudo yum -y install python36-devel python36-pip
sudo ln -s /usr/bin/pip-3.6 /usr/bin/pip3
mkdir lambda && cd lambda
STATIC_DEPS=true pip3 install -t . lxml
zip -r ~/deps.zip *

将它带到一个新的水平,使用无服务器和docker来处理所有事情。这是一篇博客文章,展示了这一点: https://serverless.com/blog/serverless-python-packaging/

答案 2 :(得分:2)

AWS Lambda使用特殊版本的Linux(据我所见)。

使用“pip install a_package -t文件夹”通常是好事,因为它有助于将您的依赖项打包到将发送到Lambda的存档中,但是库,特别是二进制库必须兼容使用lambda上的OS和Python版本。

您可以使用Python中包含的xml模块:https://docs.python.org/2/library/xml.etree.elementtree.html

如果你真的需要lxml,这个链接提供了一些如何为Lambda编译共享库的技巧: http://www.perrygeo.com/running-python-with-compiled-code-on-aws-lambda.html

答案 3 :(得分:2)

在Mask的答案上稍微扩展一下。在特别安装lxml的情况下, libxslt和libxml2库已经安装在执行AWS lambda的AMI上。因此,不需要像在答案 中那样使用不同的LD_LIBRARY_PATH启动子进程,但是必须在AMI映像上运行pip install lxml(也可以进行交叉编译)但我不知道如何)。

Launch an ec2 machine with Amazon Linux ami
Run the following script to accumulate dependencies:
set -e -o pipefail
sudo yum -y upgrade
sudo yum -y install gcc python-devel libxml2-devel libxslt-devel

virtualenv ~/env && cd ~/env && source bin/activate
pip install lxml
for dir in lib64/python2.7/site-packages \
    lib/python2.7/site-packages
do
    if [ -d $dir ] ; then
        pushd $dir; zip -r ~/deps.zip .; popd
    fi
done 

请注意,Marks答案的最后几个步骤被忽略了。您可以直接从包含处理程序方法的python文件中使用lxml。

答案 4 :(得分:2)

我已经使用serverless框架及其内置的Docker功能解决了这个问题。

要求:.aws文件夹中有一个AWS配置文件,可以访问。

首先,按照here的说明安装无服务器框架。然后,您可以使用命令serverless create --template aws-python3 --name my-lambda创建配置文件。它将使用简单的“ hello”功能创建一个serverless.yml文件和一个handler.py。您可以检查其是否适用于sls deploy。如果可行,则可以使用无服务器。

接下来,我们将需要一个名为"serverless-python-requirements"的附加插件来捆绑Python要求。您可以通过sls plugin install --name serverless-python-requirements安装它。

此插件是解决缺少的lxml包所需的所有魔术。在custom-> pythonRequirements部分中,您只需要添加dockerizePip: non-linux属性。您的serverless.yml文件可能如下所示:

service: producthunt-crawler

provider:
  name: aws
  runtime: python3.8

functions:
  hello:
    # some handler that imports lxml
    handler: handler.hello

plugins:
  - serverless-python-requirements

custom:
  pythonRequirements:
    fileName: requirements.txt
    dockerizePip: non-linux

    # Omits tests, __pycache__, *.pyc etc from dependencies
    slim: true

这将在预先配置的Docker容器中运行python需求的捆绑。之后,您可以运行sls deploy来查看魔术的发生,然后运行sls invoke -f my_function来检查魔术是否起作用。

以后使用无服务器部署和添加dockerizePip: non-linux选项时,请确保使用sls requirements clean清理已构建的需求。否则,它将仅使用已构建的东西。

答案 5 :(得分:1)

通过遵循this页上的自述文件,我可以使此工作正常进行:

  1. 在安装了docker的情况下,运行以下命令(将python3.8替换为用于lambda函数的python版本,将lxml替换为您要使用的lxml的版本)
    $ docker run -v $(pwd):/outputs -it lambci/lambda:build-python3.8 \
          pip install lxml -t /outputs/
    
  2. 这将在您的工作目录中创建一个名为lxml的文件夹,并且可能会忽略其他一些文件夹。将lxml文件夹移至与您用作lambda处理程序的.py文件相同的目录。
  3. 如果使用virtualenv,则使用lxml文件夹以及所有软件包压缩.py文件。我有一个virtualenv,而lxml已经存在于我的site-packages文件夹中,因此我必须先删除它。这是我运行的命令(请注意,我的virtualenv v-env文件夹与.py文件位于同一目录中):
    FUNCTION_NAME="name_of_your_python_file"
    cd v-env/lib/python3.8/site-packages &&
    rm -rf lxml &&
    rm -rf lxml-4.5.1.dist-info &&
    zip -r9 ${OLDPWD}/${FUNCTION_NAME}.zip . &&
    cd ${OLDPWD} &&
    zip -g ${FUNCTION_NAME}.zip ${FUNCTION_NAME}.py && 
    zip -r9 ${FUNCTION_NAME}.zip lxml
    
  4. 如果您没有virtualenv或任何其他依赖项,则可以运行
    FUNCTION_NAME="name_of_your_python_file"
    zip -g ${FUNCTION_NAME}.zip ${FUNCTION_NAME}.py && 
    zip -r9 ${FUNCTION_NAME}.zip lxml
    
  5. 将$ {FUNCTION_NAME} .zip上传到您的lambda函数中,然后照常使用。

有关使用virtualenv here为lambda创建.zip文件的更多信息

答案 6 :(得分:0)

lxml库是os依赖的,因此我们需要具有预编译的副本。步骤如下。

  1. 创建一个Docker容器。
    docker run -it lambci/lambda:build-python3.8 bash

  2. 创建一个名为“ lib”的目录(任何您想要的目录)并将lxml安装到其中。 mkdir lib
    pip install lxml -t ./lib --no-deps

  3. 打开另一个cmd并运行
    docker ps

  4. 复制containerid

  5. 将文件从容器复制到主机。
    mkdir /home/libraries/opt/python/lib/python3.8/site-packages/
    docker cp <containerid>:/var/task/lib /home/libraries/opt/python/lib/python3.8/site-packages/

  6. 现在,如果您希望将lxml作为Lambda层,则可以从amazonlinux框中编译文件的lxml副本。导航至/home/libraries/opt并压缩名为python的文件夹。现在,您可以将zip附加在lambda中作为图层。

  7. 如果要在lambda中包含lxml库。导航到/home/libraries/opt/python/lib/python3.8/site-packages/,然后将lxml文件夹复制到您的lambda中。

答案 7 :(得分:0)

LXML对它的运行环境非常敏感。

我通过在 python:3.x-slim 容器中构建zip Lambda软件包来解决此问题:

pip install --target=. lxml
zip -r lambda.zip lambda.py lxml

图片容器版本必须与Lambda中使用的python引擎版本相同

使用python 3.6、3.7和3.8成功测试

答案 8 :(得分:0)

您可以在此处找到此项目和大多数其他项目的 whl 文件; https://pypi.org/project/lxml/#files