使用 boto3 列出存储桶的内容

Posted

技术标签:

【中文标题】使用 boto3 列出存储桶的内容【英文标题】:Listing contents of a bucket with boto3 【发布时间】:2015-07-26 18:17:40 【问题描述】:

如何使用boto3 查看 S3 中存储桶内的内容? (即做一个"ls")?

执行以下操作:

import boto3
s3 = boto3.resource('s3')
my_bucket = s3.Bucket('some/path/')

返回:

s3.Bucket(name='some/path/')

如何查看其内容?

【问题讨论】:

use ## list_content def list_content(self, bucket_name): content = self.s3.list_objects_v2(Bucket=bucket_name) print(content) 其他版本已折旧。 【参考方案1】:

查看内容的一种方法是:

for my_bucket_object in my_bucket.objects.all():
    print(my_bucket_object)

【讨论】:

我可以使用 boto3 获取存储桶中特定路径下的密钥或具有特定分隔符的密钥吗?? 您应该可以说mybucket.objects.filter(Prefix='foo/bar'),它只会列出带有该前缀的对象。也可以传递Delimiter 参数。 不使用 boto3 AttributeError: 'S3' object has no attribute 'objects' @garnaat 您提到过滤器方法的评论确实帮助了我(我的代码最终变得更简单、更快)-谢谢! 我建议不要使用 object 作为变量名,因为它会影响全局类型 object【参考方案2】:

这类似于“ls”,但它不考虑前缀文件夹约定,并将列出存储桶中的对象。由读者过滤掉作为键名一部分的前缀。

在 Python 2 中:

from boto.s3.connection import S3Connection

conn = S3Connection() # assumes boto.cfg setup
bucket = conn.get_bucket('bucket_name')
for obj in bucket.get_all_keys():
    print(obj.key)

在 Python 3 中:

from boto3 import client

conn = client('s3')  # again assumes boto.cfg setup, assume AWS S3
for key in conn.list_objects(Bucket='bucket_name')['Contents']:
    print(key['Key'])

【讨论】:

如果你也想使用前缀,你可以这样做:conn.list_objects(Bucket='bucket_name', Prefix='prefix_string')['Contents'] 这只会列出前 1000 个键。来自文档字符串:“返回存储桶中的部分或全部(最多 1000 个)对象。”此外,建议您使用 list_objects_v2 而不是 list_objects(尽管这也只返回前 1000 个键)。 这个限制应该使用Paginators来处理 能否给个boto.cfg格式? @markonovak 如果有 none 则会严重崩溃。意味着我需要在那里留一个哨兵。【参考方案3】:

我假设您已经单独配置了身份验证。

import boto3
s3 = boto3.resource('s3')

my_bucket = s3.Bucket('bucket_name')

for file in my_bucket.objects.all():
    print(file.key)

【讨论】:

【参考方案4】:

我的s3 keys utility function 本质上是@Hephaestus 答案的优化版本:

import boto3


s3_paginator = boto3.client('s3').get_paginator('list_objects_v2')


def keys(bucket_name, prefix='/', delimiter='/', start_after=''):
    prefix = prefix[1:] if prefix.startswith(delimiter) else prefix
    start_after = (start_after or prefix) if prefix.endswith(delimiter) else start_after
    for page in s3_paginator.paginate(Bucket=bucket_name, Prefix=prefix, StartAfter=start_after):
        for content in page.get('Contents', ()):
            yield content['Key']

在我的测试中(boto3 1.9.84),它比等效(但更简单)的代码要快得多:

import boto3


def keys(bucket_name, prefix='/', delimiter='/'):
    prefix = prefix[1:] if prefix.startswith(delimiter) else prefix
    bucket = boto3.resource('s3').Bucket(bucket_name)
    return (_.key for _ in bucket.objects.filter(Prefix=prefix))

作为S3 guarantees UTF-8 binary sorted results,在第一个函数中添加了start_after优化。

【讨论】:

这是迄今为止最好的答案。当我向下滚动时,我只是在修改@Hephaestus 的答案(因为它是最高的)。这应该是公认的答案,并且应该因为简洁而获得加分。我要补充一点,第二个代码的生成器需要包含在 list() 中以返回文件列表。 @RichardD 两个结果都返回生成器。我使用此代码定位的许多存储桶的键数超过了代码执行器一次可以处理的内存(例如,AWS Lambda);我更喜欢在生成密钥时使用它们。 这是一个不错的解决方案,您可以将Delimiter=delimiter 添加到s3_paginator.paginate 调用以避免递归到“子目录”。【参考方案5】:

为了处理大型键列表(即当目录列表大于 1000 项时),我使用以下代码来累积具有多个列表的键值(即文件名)(感谢上面的 Amelio 第一行)。代码适用于python3:

    from boto3  import client
    bucket_name = "my_bucket"
    prefix      = "my_key/sub_key/lots_o_files"

    s3_conn   = client('s3')  # type: BaseClient  ## again assumes boto.cfg setup, assume AWS S3
    s3_result =  s3_conn.list_objects_v2(Bucket=bucket_name, Prefix=prefix, Delimiter = "/")

    if 'Contents' not in s3_result:
        #print(s3_result)
        return []

    file_list = []
    for key in s3_result['Contents']:
        file_list.append(key['Key'])
    print(f"List count = len(file_list)")

    while s3_result['IsTruncated']:
        continuation_key = s3_result['NextContinuationToken']
        s3_result = s3_conn.list_objects_v2(Bucket=bucket_name, Prefix=prefix, Delimiter="/", ContinuationToken=continuation_key)
        for key in s3_result['Contents']:
            file_list.append(key['Key'])
        print(f"List count = len(file_list)")
    return file_list

【讨论】:

【参考方案6】:

如果你想传递 ACCESS 和 SECRET 密钥(你不应该这样做,因为它不安全):

from boto3.session import Session

ACCESS_KEY='your_access_key'
SECRET_KEY='your_secret_key'

session = Session(aws_access_key_id=ACCESS_KEY,
                  aws_secret_access_key=SECRET_KEY)
s3 = session.resource('s3')
your_bucket = s3.Bucket('your_bucket')

for s3_file in your_bucket.objects.all():
    print(s3_file.key)

【讨论】:

这不如在 ~/.aws/credentials 中拥有凭证文件安全。虽然这是一个有效的解决方案。 这需要将机密提交到源代码控制。不好。 这个答案没有添加任何关于列出对象的 API / 机制的内容,同时添加了一个非相关的身份验证方法,这对所有 boto 资源都很常见,并且在安全方面是一种不好的做法 在关于安全的答案中添加了免责声明。 如果密钥是由 Vault (Hashicorp) 等密钥/秘密管理系统提供的,那岂不是比将凭证文件放在 ~/.aws/credentials 更好吗?【参考方案7】:

一种更简洁的方式,而不是通过 for 循环进行迭代,您也可以只打印包含 S3 存储桶内所有文件的原始对象:

session = Session(aws_access_key_id=aws_access_key_id,aws_secret_access_key=aws_secret_access_key)
s3 = session.resource('s3')
bucket = s3.Bucket('bucket_name')

files_in_s3 = bucket.objects.all() 
#you can print this iterable with print(list(files_in_s3))

【讨论】:

@petezurich ,你能解释一下为什么我的答案如此微小的编辑 - 在我的答案开头用大写的“A”替换“a”会降低我的声誉 -2 但是我认为您和我都同意,您的更正不仅根本不相关,而且实际上相当琐碎,您不会这么说吗?请专注于内容而不是幼稚的修改,最有义务的老男孩 这是两种不同的交互方式。 1. 我编辑了你的答案,即使是轻微的拼写错误也推荐。我同意,次要和琐碎之间的界限是模棱两可的。我不会对任何帖子投反对票,因为我看到了错误,而在这种情况下我没有。我只是修复了我看到的所有错误。 2.我对您的回答投了反对票,因为您写道files_in_s3是一个“列表对象”。 Python中没有这样的东西。它是一个可迭代的,我无法让你的代码工作,因此被否决了。比我发现错误并看到您的观点但无法撤消我的反对意见。 @petezurich 没问题,理解你的观点,只有一件事,在 Python 中,列表是一个对象,因为在 python 中几乎所有东西都是一个对象,那么它也遵循一个列表也是一个可迭代的,但首先,它是一个对象!这就是为什么我不理解您的反对票的原因-您反对的是正确且有效的代码。不管怎样,谢谢你的道歉,祝你一切顺利 @petezurich Python 中的一切都是对象。 “列表对象”是完全可以接受的。【参考方案8】:
#To print all filenames in a bucket
import boto3

s3 = boto3.client('s3')

def get_s3_keys(bucket):

    """Get a list of keys in an S3 bucket."""
    resp = s3.list_objects_v2(Bucket=bucket)
    for obj in resp['Contents']:
      files = obj['Key']
    return files

  
filename = get_s3_keys('your_bucket_name')

print(filename)

#To print all filenames in a certain directory in a bucket
import boto3

s3 = boto3.client('s3')

def get_s3_keys(bucket, prefix):

    """Get a list of keys in an S3 bucket."""
    resp = s3.list_objects_v2(Bucket=bucket, Prefix=prefix)
    for obj in resp['Contents']:
      files = obj['Key']
      print(files)
    return files

  
filename = get_s3_keys('your_bucket_name', 'folder_name/sub_folder_name/')

print(filename)

更新: 最简单的方法是使用awswrangler

import awswrangler as wr
wr.s3.list_objects('s3://bucket_name')

【讨论】:

“get_s3_keys”都只返回最后一个键。 这会列出存储桶中的所有文件;问题是如何做ls。你会怎么做..只打印根目录中的文件 它返回最后一个键,使用这个:def get_s3_keys(bucket, prefix): resp = s3.list_objects_v2(Bucket=bucket, Prefix=prefix) return [obj['Key'] for obj in resp['Contents']]【参考方案9】:

对象摘要:

有两个标识符附加到 ObjectSummary:

bucket_name 键

boto3 S3: ObjectSummary

AWS S3 文档中有关对象键的更多信息:

对象键:

在创建对象时,您指定键名,该键名唯一标识存储桶中的对象。例如,在 Amazon S3 控制台(请参阅 AWS 管理控制台)中,当您突出显示存储桶时,会显示存储桶中的对象列表。这些名称是对象键。键名是一个 Unicode 字符序列,其 UTF-8 编码长度最多为 1024 个字节。

Amazon S3 数据模型是一种扁平结构:您创建一个存储桶,该存储桶存储对象。没有子桶或子文件夹的层次结构;但是,您可以像 Amazon S3 控制台那样使用键名前缀和分隔符来推断逻辑层次结构。 Amazon S3 控制台支持文件夹的概念。假设您的存储桶(管理员创建)有四个对象,对象键如下:

开发/Projects1.xls

财务/statement1.pdf

私人/税务文件.pdf

s3-dg.pdf

参考:

AWS S3: Object Keys

这里是一些示例代码,演示了如何获取存储桶名称和对象键。

示例:

import boto3
from pprint import pprint

def main():

    def enumerate_s3():
        s3 = boto3.resource('s3')
        for bucket in s3.buckets.all():
             print("Name: ".format(bucket.name))
             print("Creation Date: ".format(bucket.creation_date))
             for object in bucket.objects.all():
                 print("Object: ".format(object))
                 print("Object bucket_name: ".format(object.bucket_name))
                 print("Object key: ".format(object.key))

    enumerate_s3()


if __name__ == '__main__':
    main()

【讨论】:

【参考方案10】:
import boto3
s3 = boto3.resource('s3')

## Bucket to use
my_bucket = s3.Bucket('city-bucket')

## List objects within a given prefix
for obj in my_bucket.objects.filter(Delimiter='/', Prefix='city/'):
  print obj.key

输出:

city/pune.csv
city/goa.csv

【讨论】:

此命令还包括目录,即city/city/pune.csvcity/goa.csv【参考方案11】:

这是一个简单的函数,它返回所有文件的文件名或具有某些类型的文件,例如“json”、“jpg”。

def get_file_list_s3(bucket, prefix="", file_extension=None):
            """Return the list of all file paths (prefix + file name) with certain type or all
            Parameters
            ----------
            bucket: str
                The name of the bucket. For example, if your bucket is "s3://my_bucket" then it should be "my_bucket"
            prefix: str
                The full path to the the 'folder' of the files (objects). For example, if your files are in 
                s3://my_bucket/recipes/deserts then it should be "recipes/deserts". Default : ""
            file_extension: str
                The type of the files. If you want all, just leave it None. If you only want "json" files then it
                should be "json". Default: None       
            Return
            ------
            file_names: list
                The list of file names including the prefix
            """
            import boto3
            s3 = boto3.resource('s3')
            my_bucket = s3.Bucket(bucket)
            file_objs =  my_bucket.objects.filter(Prefix=prefix).all()
            file_names = [file_obj.key for file_obj in file_objs if file_extension is not None and file_obj.key.split(".")[-1] == file_extension]
            return file_names

【讨论】:

【参考方案12】:

所以你在 boto3 中要求 aws s3 ls 的等价物。这将列出所有***文件夹和文件。这是我能得到的最接近的;它只列出所有***文件夹。这么简单的操作竟然这么难,令人惊讶。

import boto3

def s3_ls():
  s3 = boto3.resource('s3')
  bucket = s3.Bucket('example-bucket')
  result = bucket.meta.client.list_objects(Bucket=bucket.name,
                                           Delimiter='/')
  for o in result.get('CommonPrefixes'):
    print(o.get('Prefix'))

【讨论】:

超级好用!将Prefix= 添加到list_objects 以限制为该前缀。 这很好用!只列出前缀内的***对象!谢谢!【参考方案13】:

我曾经这样做的一种方式:

import boto3
s3 = boto3.resource('s3')
bucket=s3.Bucket("bucket_name")
contents = [_.key for _ in bucket.objects.all() if "subfolders/ifany/" in _.key]

【讨论】:

【参考方案14】:

我就是这么干的,包括认证方式:

s3_client = boto3.client(
                's3',
                aws_access_key_id='access_key',
                aws_secret_access_key='access_key_secret',
                config=boto3.session.Config(signature_version='s3v4'),
                region_name='region'
            )

response = s3_client.list_objects(Bucket='bucket_name', Prefix=key)
if ('Contents' in response):
    # Object / key exists!
    return True
else:
    # Object / key DOES NOT exist!
    return False

【讨论】:

【参考方案15】:

解决办法

import boto3

s3=boto3.resource('s3')
BUCKET_NAME = 'Your S3 Bucket Name'
allFiles = s3.Bucket(BUCKET_NAME).objects.all()
for file in allFiles:
    print(file.key)

【讨论】:

【参考方案16】:

在上述 cmets 之一中对 @Hephaeastus 的代码稍作修改,编写了以下方法来列出给定路径中的文件夹和对象(文件)。工作原理类似于 s3 ls 命令。

from boto3 import session

def s3_ls(profile=None, bucket_name=None, folder_path=None):
    folders=[]
    files=[]
    result=dict()
    bucket_name = bucket_name
    prefix= folder_path
    session = boto3.Session(profile_name=profile)
    s3_conn   = session.client('s3')
    s3_result =  s3_conn.list_objects_v2(Bucket=bucket_name, Delimiter = "/", Prefix=prefix)
    if 'Contents' not in s3_result and 'CommonPrefixes' not in s3_result:
        return []

    if s3_result.get('CommonPrefixes'):
        for folder in s3_result['CommonPrefixes']:
            folders.append(folder.get('Prefix'))

    if s3_result.get('Contents'):
        for key in s3_result['Contents']:
            files.append(key['Key'])

    while s3_result['IsTruncated']:
        continuation_key = s3_result['NextContinuationToken']
        s3_result = s3_conn.list_objects_v2(Bucket=bucket_name, Delimiter="/", ContinuationToken=continuation_key, Prefix=prefix)
        if s3_result.get('CommonPrefixes'):
            for folder in s3_result['CommonPrefixes']:
                folders.append(folder.get('Prefix'))
        if s3_result.get('Contents'):
            for key in s3_result['Contents']:
                files.append(key['Key'])

    if folders:
        result['folders']=sorted(folders)
    if files:
        result['files']=sorted(files)
    return result

这会列出给定路径中的所有对象/文件夹。默认情况下,Folder_path 可以保留为 None 并且方法将列出存储桶根目录的直接内容。

【讨论】:

【参考方案17】:

也可以这样做:

csv_files = s3.list_objects_v2(s3_bucket_path)
    for obj in csv_files['Contents']:
        key = obj['Key']

【讨论】:

【参考方案18】:

一个不错的选择也可能是从 lambda 函数运行 aws cli 命令

import subprocess
import logging

logger = logging.getLogger()
logger.setLevel(logging.INFO)

def run_command(command):
    command_list = command.split(' ')

    try:
        logger.info("Running shell command: \"\"".format(command))
        result = subprocess.run(command_list, stdout=subprocess.PIPE);
        logger.info("Command output:\n---\n\n---".format(result.stdout.decode('UTF-8')))
    except Exception as e:
        logger.error("Exception: ".format(e))
        return False

    return True

def lambda_handler(event, context):
    run_command('/opt/aws s3 ls s3://bucket-name')

【讨论】:

【参考方案19】:

使用cloudpathlib

cloudpathlib 提供了一个便利的包装器,以便您可以使用简单的pathlib API 与 AWS S3(以及 Azure blob 存储、GCS 等)进行交互。您可以使用pip install "cloudpathlib[s3]" 安装。

pathlib 一样,您可以使用globiterdir 列出目录的内容。

这是一个公共 AWS S3 存储桶的示例,您可以复制并粘贴它以运行。

from cloudpathlib import CloudPath

s3_path = CloudPath("s3://ladi/Images/FEMA_CAP/2020/70349")

# list items with glob
list(
    s3_path.glob("*")
)[:3]
#> [ S3Path('s3://ladi/Images/FEMA_CAP/2020/70349/DSC_0001_5a63d42e-27c6-448a-84f1-bfc632125b8e.jpg'),
#>   S3Path('s3://ladi/Images/FEMA_CAP/2020/70349/DSC_0002_a89f1b79-786f-4dac-9dcc-609fb1a977b1.jpg'),
#>   S3Path('s3://ladi/Images/FEMA_CAP/2020/70349/DSC_0003_02c30af6-911e-4e01-8c24-7644da2b8672.jpg')]

# list items with iterdir
list(
    s3_path.iterdir()
)[:3]
#> [ S3Path('s3://ladi/Images/FEMA_CAP/2020/70349/DSC_0001_5a63d42e-27c6-448a-84f1-bfc632125b8e.jpg'),
#>   S3Path('s3://ladi/Images/FEMA_CAP/2020/70349/DSC_0002_a89f1b79-786f-4dac-9dcc-609fb1a977b1.jpg'),
#>   S3Path('s3://ladi/Images/FEMA_CAP/2020/70349/DSC_0003_02c30af6-911e-4e01-8c24-7644da2b8672.jpg')]

reprexlitev0.4.2 创建于 2021-05-21 20:38:47 PDT

【讨论】:

以上是关于使用 boto3 列出存储桶的内容的主要内容,如果未能解决你的问题,请参考以下文章

Pyspark 从 S3 存储桶的子目录中读取所有 JSON 文件

数据流:storage.Client() 导入错误或如何列出 GCP 存储桶的所有 blob

如何在谷歌存储桶中列出所有上传到存储桶的文件?

列出 AWS S3 存储桶的特定“文件夹”中的文件

如何列出所有未使用的弹性IP并使用boto3释放它们

使用 boto3 列出 100 多个堆栈