Вывести список содержимого каталога S3, используя Python и Boto3?

Я пытаюсь составить список всех каталогов в корзине S3, используя Python и Boto3.

Я использую следующий код:

s3 = session.resource('s3')  # I already have a boto3 Session object
bucket_names = [
    'this/bucket/',
    'that/bucket/'
]
for name in bucket_names:
    bucket = s3.Bucket(name)
    for obj in bucket.objects.all():  # this raises an exception
        # handle obj

При запуске я получаю следующую трассировку стека исключений:

File "botolist.py", line 67, in <module>
  for obj in bucket.objects.all():
File "/Library/Python/2.7/site-packages/boto3/resources/collection.py", line 82, in __iter__
  for page in self.pages():
File "/Library/Python/2.7/site-packages/boto3/resources/collection.py", line 165, in pages
  for page in pages:
File "/Library/Python/2.7/site-packages/botocore/paginate.py", line 83, in __iter__
  response = self._make_request(current_kwargs)
File "/Library/Python/2.7/site-packages/botocore/paginate.py", line 155, in _make_request
  return self._method(**current_kwargs)
File "/Library/Python/2.7/site-packages/botocore/client.py", line 270, in _api_call
  return self._make_api_call(operation_name, kwargs)
File "/Library/Python/2.7/site-packages/botocore/client.py", line 335, in _make_api_call
  raise ClientError(parsed_response, operation_name)

botocore.exceptions.ClientError: An error occurred (NoSuchKey) when calling the ListObjects operation: The specified key does not exist.

Как правильно составить список каталогов внутри корзины?

Ответ 1

Все эти другие ответы отстой. С помощью

client.list_objects()

Ограничивает вас до 1k результатов макс. Остальные ответы либо неверны, либо слишком сложны.

Работа с маркером продолжения - ужасная идея. Просто используйте paginator, который имеет дело с этой логикой для вас

Решение, которое вы хотите:

[e['Key'] for p in client.get_paginator("list_objects_v2")\
                         .paginate(Bucket='my_bucket')
          for e in p['Contents']]

Ответ 2

В качестве альтернативы вы можете использовать boto3.client

Пример

>>> import boto3 
>>> client = boto3.client('s3')
>>> client.list_objects(Bucket='MyBucket')

list_objects также поддерживает другие аргументы, которые могут потребоваться для итерации, но результат: Bucket, Delimiter, EncodingType, Marker, MaxKeys, Prefix

Ответ 3

Если у вас есть сеанс, создайте клиент и получите CommonPrefixes клиентов list_objects:

client = session.client('s3', 
                        # region_name='eu-west-1'
                        )

result = client.list_objects(Bucket='MyBucket', Delimiter='/')
for obj in result.get('CommonPrefixes'):
    #handle obj.get('Prefix')

Там может быть много папок, и вы можете захотеть начать в подпапке. Что-то вроде этого может справиться с этим:

def folders(client, bucket, prefix=''):
    paginator = client.get_paginator('list_objects')
    for result in paginator.paginate(Bucket=bucket, Prefix=prefix, Delimiter='/'):
        for prefix in result.get('CommonPrefixes', []):
            yield prefix.get('Prefix')

gen_folders = folders(client, 'MyBucket')
list(gen_folders)

gen_subfolders = folders(client, 'MyBucket', prefix='MySubFolder/')
list(gen_subfolders)

Ответ 4

Лучший способ получить список ВСЕХ объектов с определенным префиксом в list_objects_v2 S3 - это использовать list_objects_v2 вместе с ContinuationToken для преодоления предела разбиения на 1000 объектов.

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

s3_bucket = 'your-bucket'
s3_prefix = 'your/prefix'
partial_list = s3.list_objects_v2(
        Bucket=s3_bucket, 
        Prefix=s3_prefix)
obj_list = partial_list['Contents']
while partial_list['IsTruncated']:
    next_token = partial_list['NextContinuationToken']
    partial_list = s3.list_objects_v2(
        Bucket=s3_bucket, 
        Prefix=s3_prefix, 
        ContinuationToken=next_token)
    obj_list.extend(partial_list['Contents'])

Ответ 5

Я бы подумал, что вы не можете иметь косую черту в имени ведра. Вы говорите, что хотите перечислить все каталоги в ведре, но ваш код пытается перечислить все содержимое (не обязательно каталоги) в нескольких ведрах. Вероятно, эти ведра не существуют (потому что у них есть незаконные имена). Поэтому, когда вы запускаете

bucket = s3.Bucket(name)

bucket, вероятно, имеет значение null, а последующий список не будет выполнен.

Ответ 6

Я знаю, что это старо, но я наткнулся на него и хотел уточнить кого-нибудь, кто его найдет.

У меня недостаточно репутации, чтобы добавить комментарий к ответу @Vor, но он кажется правильным. Разница между их примером и OP заключается в том, что @Vor вызывает s3-клиент, в то время как OP вызывает ресурс s3:

@Vor:

client = boto3.client('s3')

OP:

s3 = session.resource('s3')

Если это вам полезно, +1 сообщение @Vor.