【问题标题】:How to download the latest file of an S3 bucket using Boto3?如何使用 Boto3 下载 S3 存储桶的最新文件?
【发布时间】:2018-01-04 16:06:43
【问题描述】:

我能找到的其他问题是指较旧版本的 Boto。我想下载 S3 存储桶的最新文件。在documentation 中,我发现有一个方法 list_object_versions() 可以为您提供一个布尔值 IsLatest。不幸的是,我只设法建立连接并下载文件。您能否告诉我如何扩展我的代码以获取存储桶的最新文件?谢谢

import boto3
conn = boto3.client('s3',
                    region_name="eu-west-1",
                    endpoint_url="customendpoint",
                    config=Config(signature_version="s3", s3={'addressing_style': 'path'}))

从这里我不知道如何从名为mytestbucket 的存储桶中获取最新添加的文件。存储桶中有各种 csv 文件,但名称当然不同。

更新:

import boto3
from botocore.client import Config

s3 = boto3.resource('s3', region_name="eu-west-1", endpoint_url="custom endpoint", aws_access_key_id = '1234', aws_secret_access_key = '1234', config=Config(signature_version="s3", s3={'addressing_style': 'path'}))
my_bucket = s3.Bucket('mytestbucket22')
unsorted = []
for file in my_bucket.objects.filter():
   unsorted.append(file)

files = [obj.key for obj in sorted(unsorted, key=get_last_modified, reverse=True)][0:9]

这给了我以下错误:

NameError: name 'get_last_modified' is not defined

【问题讨论】:

    标签: python amazon-web-services amazon-s3 boto boto3


    【解决方案1】:

    我提供的答案的变体:Boto3 S3, sort bucket by last modified。您可以根据需要修改代码。

    get_last_modified = lambda obj: int(obj['LastModified'].strftime('%s'))
    
    s3 = boto3.client('s3')
    objs = s3.list_objects_v2(Bucket='my_bucket')['Contents']
    last_added = [obj['Key'] for obj in sorted(objs, key=get_last_modified)][0]
    

    如果要反转排序:

    [obj['Key'] for obj in sorted(objs, key=get_last_modified, reverse=True)][0]
    

    【讨论】:

    • 谢谢。我将配置添加到客户端并编辑了存储桶名称,但出现以下错误:get_last_modified = lambda obj: int(obj['LastModified'].strftime('%s')) ValueError: Invalid format string
    • 您使用的是Python 2.7 还是Python 3
    • 我使用的是 3.6.1。
    • 如果您想要最新添加的文件,我认为您应该将[0] 修改为[-1]
    • @MattBunch 是的,如果桶有超过1000个对象,你需要分页,获取所有对象然后排序。
    【解决方案2】:

    你可以的

    import boto3
    
    s3_client = boto3.client('s3')
    response = s3_client.list_objects_v2(Bucket='bucket_name', Prefix='prefix')
    all = response['Contents']        
    latest = max(all, key=lambda x: x['LastModified'])
    

    【讨论】:

    • 因此,如果您正在寻找最新更新的文件夹,您可以继续使用latest['Key'].split('/')[1]
    【解决方案3】:

    如果你有很多文件,那么你需要使用 helloV 提到的分页。我就是这样做的。

    get_last_modified = lambda obj: int(obj['LastModified'].strftime('%s'))
    s3 = boto3.client('s3')
    paginator = s3.get_paginator( "list_objects" )
    page_iterator = paginator.paginate( Bucket = "BucketName", Prefix = "Prefix")
    for page in page_iterator:
        if "Contents" in page:
            last_added = [obj['Key'] for obj in sorted( page["Contents"], key=get_last_modified)][-1]
    

    【讨论】:

      【解决方案4】:

      当 s3 存储桶中有超过 1000 个对象时,这会处理。这基本上是@SaadK 的答案,没有 for 循环并为 list_objects_v2 使用更新版本。

      编辑:修复了@Timothée-Jeannin 确定的问题。确保标识所有页面的最新版本。

      https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/s3.html#S3.Paginator.ListObjectsV2

      import boto3
      
      def get_most_recent_s3_object(bucket_name, prefix):
          s3 = boto3.client('s3')
          paginator = s3.get_paginator( "list_objects_v2" )
          page_iterator = paginator.paginate(Bucket=bucket_name, Prefix=prefix)
          latest = None
          for page in page_iterator:
              if "Contents" in page:
                  latest2 = max(page['Contents'], key=lambda x: x['LastModified'])
                  if latest is None or latest2['LastModified'] > latest['LastModified']:
                      latest = latest2
          return latest
      
      latest = get_most_recent_s3_object(bucket_name, prefix)
      
      latest['Key']  # -->   'prefix/objectname'
      

      【讨论】:

      • 这不是错误的吗?如果有多个页面,这将给出最后一页的最新对象,因为它可能会在每次迭代时重新定义。
      • 只是为了让下一个人不必仔细阅读/检查编辑历史记录:问题已得到修复
      【解决方案5】:

      如果你像我一样使用Session,这与 helloV 的答案基本相同。

      from boto3.session import Session
      import settings
      
      session = Session(aws_access_key_id=settings.AWS_ACCESS_KEY_ID,
                                aws_secret_access_key=settings.AWS_SECRET_ACCESS_KEY)
      s3 = session.resource("s3")
      
      get_last_modified = lambda obj: int(obj.last_modified.strftime('%s'))
      
      
      bckt = s3.Bucket("my_bucket")
      objs = [obj for obj in bckt.objects.all()]
      
      objs = [obj for obj in sorted(objs, key=get_last_modified)]
      last_added = objs[-1].key
      

      objs 排序后,您可以快速删除除最新的文件以外的所有文件

      for obj in objs[:-1]:
          s3.Object("my_bucket", obj.key).delete()
      

      【讨论】:

        【解决方案6】:

        您应该能够使用默认下载文件命令下载文件的最新版本

        import boto3
        import botocore
        
        BUCKET_NAME = 'mytestbucket'
        KEY = 'fileinbucket.txt'
        
        s3 = boto3.resource('s3')
        
        try:
            s3.Bucket(BUCKET_NAME).download_file(KEY, 'downloadname.txt')
        except botocore.exceptions.ClientError as e:
            if e.response['Error']['Code'] == "404":
                print("The object does not exist.")
            else:
                raise
        

        参考link

        要获取最后修改或上传的文件,您可以使用以下方法

        s3 = boto3.resource('s3')
        my_bucket = s3.Bucket('myBucket')
        unsorted = []
        for file in my_bucket.objects.filter():
           unsorted.append(file)
        
        files = [obj.key for obj in sorted(unsorted, key=get_last_modified, 
            reverse=True)][0:9]
        

        正如本参考文献link 中的回答所说,它不是最佳的,但它可以工作。

        【讨论】:

        • 谢谢。也许我的问题不够清楚。我刚刚对其进行了编辑并提供了更多信息。我想从包含几个 csv 文件的存储桶中下载最新的文件,并且无论它的名称是什么,我都想始终下载最新的文件。
        • 某种意义上的最新版本,而不是特定文件的最新版本?还是最后添加的文件?
        • 最新添加的文件。
        • 谢谢。不幸的是,这向我展示了另一个错误。我已经把它放在我的问题中了。我必须导入其他东西吗?
        【解决方案7】:

        我还想从 s3 存储桶下载最新文件,但位于特定文件夹中。使用以下函数使用存储桶名称和前缀(即文件夹名称)获取最新文件名。

        import boto3
        
        def get_latest_file_name(bucket_name,prefix):
            """
            Return the latest file name in an S3 bucket folder.
        
            :param bucket: Name of the S3 bucket.
            :param prefix: Only fetch keys that start with this prefix (folder  name).
            """
            s3_client = boto3.client('s3')
            objs = s3_client.list_objects_v2(Bucket=bucket_name)['Contents']
            shortlisted_files = dict()            
            for obj in objs:
                key = obj['Key']
                timestamp = obj['LastModified']
                # if key starts with folder name retrieve that key
                if key.startswith(prefix):              
                    # Adding a new key value pair
                    shortlisted_files.update( {key : timestamp} )   
            latest_filename = max(shortlisted_files, key=shortlisted_files.get)
            return latest_filename
        
        latest_filename = get_latest_file_name(bucket_name='use_your_bucket_name',prefix = 'folder_name/')
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2022-01-09
          • 2015-11-02
          • 2023-03-29
          • 1970-01-01
          • 2020-11-05
          • 2018-12-31
          • 2020-05-26
          • 2016-11-18
          相关资源
          最近更新 更多