简体   繁体   English

Python AWS Lambda S3: [Errno 2] 没有这样的文件或目录: 'which'

[英]Python AWS Lambda S3: [Errno 2] No such file or directory: 'which'

I am trying to convert the HTML file to pdf and upload it in S3 using Python 3.8 and lambda. I have created a deployment package using pdfkit but while converting to pdf, getting error "[Errno 2] No such file or directory: 'which'".我正在尝试将 HTML 文件转换为 pdf 并使用 Python 3.8 和 lambda 将其上传到 S3。我已经使用 pdfkit 创建了一个部署 package,但是在转换为 pdf 时出现错误:“[Err '”。 The same piece of code works on my local machine with the local path.同一段代码在我的本地机器上使用本地路径工作。

I also tried to create a txt file in /tmp to make sure I have access and it was successfully able to create a file and from there upload to S3.我还尝试在 /tmp 中创建一个 txt 文件以确保我有访问权限并且它能够成功创建一个文件并从那里上传到 S3。 Please help me here.请在这里帮助我。

    s3_upload = boto3.resource('s3')
    bucket_name = 'bucket-invoice'
    html_body = '<html>Hello from test-resource</html>'
    writeFileName = 'test_invoice.pdf'
    local_file_path = '/tmp/local_pdf_file.pdf'

    print('Step 1: ' + local_file_path, html_body)
    pdfkit.from_string(html_body, local_file_path)  # <-- Getting error here

    # Write to S3:
    print('Step 2: Uploading in S3')
    s3_upload.meta.client.upload_file(local_file_path, bucket_name, writeFileName)

    print('Step 3: upload done')

Error Message:错误信息:

Response:
{
  "errorMessage": "[Errno 2] No such file or directory: 'which'",
  "errorType": "FileNotFoundError",
  "stackTrace": [
    "  File \"/var/task/invoice_api.py\", line 49, in lambda_handler\n    generate_pdf_2()\n",
    "  File \"/var/task/invoice_api.py\", line 161, in generate_pdf_2\n    pdfkit.from_string(html_body, local_file_path)\n",
    "  File \"/var/task/pdfkit/api.py\", line 69, in from_string\n    r = PDFKit(input, 'string', options=options, toc=toc, cover=cover, css=css,\n",
    "  File \"/var/task/pdfkit/pdfkit.py\", line 42, in __init__\n    self.configuration = (Configuration() if configuration is None\n",
    "  File \"/var/task/pdfkit/configuration.py\", line 17, in __init__\n    self.wkhtmltopdf = subprocess.Popen(\n",
    "  File \"/var/lang/lib/python3.8/subprocess.py\", line 854, in __init__\n    self._execute_child(args, executable, preexec_fn, close_fds,\n",
    "  File \"/var/lang/lib/python3.8/subprocess.py\", line 1702, in _execute_child\n    raise child_exception_type(errno_num, err_msg, err_filename)\n"
  ]
}

If you want to include libraries which are not part of Python's standard library, such as pdfkit , you can use lambda's layers .如果要包含不属于 Python 标准库的库,例如pdfkit ,则可以使用lambda 的 layers


1. Create the zip 1.创建压缩包

This is a zip which contains all the libraries you want the lambda function to use.这是一个 zip,其中包含您希望 lambda 函数使用的所有库。 First, create a folder called python :首先,创建一个名为python的文件夹:

$ mkdir python
$ cd python

then, install the Python libraries you need in there.然后,在其中安装您需要的 Python 库。 You can do this either with a single library:您可以使用单个库执行此操作:

$ pip install --target . pdfkit

or with a list of libraries (requirements.txt)或带有库列表(requirements.txt)

$ pip install --target . -r requirements.txt

finally, zip up everything.最后,把所有东西都拉上拉链。

... in Bash: ...在 Bash 中:

$ zip -r dependencies.zip ../python

... in Powershell: ...在Powershell中:

$ Compress-Archive -Path . -DestinationPath dependencies.zip

2. Create a layer 2. 创建图层

You can do this either in the AWS console or in the CLI.您可以在 AWS 控制台或 CLI 中执行此操作。 Follow these instructions .遵循这些说明


3. Add the layer to the lambda function 3. 将层添加到 lambda 函数

You can do this either with the Add a layer option in the lambda page, or in the CLI.您可以使用 lambda 页面或 CLI 中的Add a layer选项来执行此操作。 Follow these instructions .遵循这些说明

The issue is that unless it is preconfigured pdfkit is trying to call the "which" command to figure out where the wkhtmltopdf binary is.问题是,除非预先配置,否则 pdfkit 会尝试调用“which”命令来找出 wkhtmltopdf 二进制文件的位置。 But "which" is not available on the container running Lambda.但是“which”在运行 Lambda 的容器上不可用。 If you look at the pdfkit code you can call the configuration object with the contents of the binary.如果您查看 pdfkit 代码,您可以使用二进制文件的内容调用配置对象。

So for this to work, you could try the following:因此,要使其正常工作,您可以尝试以下操作:

 config = pdfkit.configuration(wkhtmltopdf=bytes('/opt/bin/wkhtmltopdf','utf-8')) pdf = pdfkit.from_string(html_body, local_file_path, configuration=config)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM