AWS Lambda(Python)-从互联网下载文件并直接上传到AWS S3

4

我想从API下载一个文件,然后直接上传(流式传输)到S3。

我的本地下载代码(完美运行)如下:

import requests
import datetime
import os

headers = {'Authorization': 'apikey THISISHIDDEN'}
baseURL = 'https://api.test.au/busschedule/'
target_path = datetime.datetime.now().strftime('%Y-%m-%d schedule') + '.zip'

response = requests.get(baseURL, stream=True, headers=headers)
handle = open(target_path, "wb")
for chunk in response.iter_content(chunk_size=512):
    if chunk:  # filter out keep-alive new chunks
        handle.write(chunk)
handle.close()

我尝试将文件下载并传输至S3(但未成功):

# import requests
import datetime
import os
import boto3
import botocore.vendored.requests.packages.urllib3 as urllib3

# Get environment variables from serverless.yml
bucket = "bucket"  
s3folder = "schedules"

# Set standard script parameters
headers = {'Authorization': 'apikey THISISHIDDEN'}
baseURL = 'https://api.test.au/busschedule/'


def run(event, context):
    s3 = boto3.client('s3')
    datetimestamp = datetime.datetime.today().strftime('%Y%m%dT%H%M%S')
    filename = datetimestamp + " bus schedule.zip"
    key = s3folder + '/' + filename  # your desired s3 path or filename
    http = urllib3.PoolManager()
    s3.upload_fileobj(http.request('GET', baseURL,
                                   headers=headers, preload_content=False),
                                   bucket, key)


def main():
  run({},{})


if __name__ == "__main__":
        exit(main())

我收到的CloudWatch返回的错误是:
InsecureRequestWarning: Unverified HTTPS request is being made.  Timeout after 300.10s.

编辑:该lambda函数的超时时间为300秒;但这应该足以下载文件(6mb)。本地下载只需要10秒左右。有没有更好的方法来处理这个问题?


这个错误意味着在初始化期间(当您的代码被导入时)引发了此未处理的异常。可能是某些代码尝试获取 os.environ['URL']。这里的代码格式不正确,有一个无效的字符串文字。顺便说一下,这段代码格式不正确,你有可能漏掉了什么? - Ronyis
非常抱歉,我在试图清理 Stack Overflow 的代码时,上传了错误的问题。我正在使用 serverless 将代码部署到 AWS Lambda,并且错误地命名了环境变量(URL)。 - dandev91
内存大小是多少?使用较小的内存大小也意味着较低的网络带宽。 - Ronyis
分配了512MB内存给一个非常小的(不到10MB)文件。 - dandev91
我建议先运行GET请求,然后进行S3上传,并添加打印语句以查看超时发生的位置。你也可以尝试获取较小的文件大小,以查看是否与问题有关。 - Ronyis
使用上述代码无法解决问题 - 已切换到另一个库。 - dandev91
2个回答

1
使用 'smart_open' 库解决了这个问题:
response = requests.get(baseURL, stream=True, headers=headers)
s3url = 's3://' + bucket + '/' + key
with smart_open(s3url, 'wb') as fout:
    fout.write(response.content)

我还有一个问题需要解决(Lambda 权限),但这将是一个单独的问题。在本地运行得非常好。


0

使用AWS Lambda上传文件的另一种方法(甚至可以上传大于6MB的文件):

步骤1:基于get或put请求创建预签名URL,并将此URL作为响应返回。 步骤2:在UI上使用此URL在您的文件上传器类中。

优点

  1. 代码在文件大小方面可扩展,因为Lambda有6MB的限制,这个逻辑适用于较少和更高的数据。
  2. 预签名URL是安全的方式,我们可以为URL提供时间限制,超过该时间限制后URL将过期。

缺点

  1. 这是一个两步骤的过程,因此需要调用2个API来上传单个文件。

请随时为此方法提供反馈。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接