web-dev-qa-db-fra.com

Comment répertorier le contenu d'un répertoire d'un compartiment S3 à l'aide de Python et Boto3?

J'essaie de répertorier tous les répertoires d'un compartiment S3 en utilisant Python et Boto3.

J'utilise le code suivant:

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

Lorsque j'exécute cela, j'obtiens la trace de pile d'exceptions suivante:

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.

Quelle est la bonne façon de répertorier les répertoires dans un compartiment?

Merci d'avance...

14
Allen Gooch

Toutes ces autres réponses sont nulles. En utilisant

client.list_objects()

Vous limite à 1k résultats max. Les autres réponses sont fausses ou trop complexes.

Traiter le jeton de continuation vous-même est une idée terrible. Utilisez simplement paginator, qui traite de cette logique pour vous

La solution que vous recherchez est:

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

Si vous avez la session, créez un client et obtenez le CommonPrefixes des clients 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')

Il pourrait y avoir beaucoup de dossiers et vous voudrez peut-être commencer dans un sous-dossier. Quelque chose comme ça pourrait gérer cela:

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)
10
Anne M.

Vous pouvez également utiliser boto3.client

Exemple

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

list_objects prend également en charge d'autres arguments qui peuvent être nécessaires pour itérer le résultat: Bucket, Delimiter, EncodingType, Marker, MaxKeys, Prefix

10
Vor

La meilleure façon d'obtenir la liste de TOUS les objets avec un préfixe spécifique dans un compartiment S3 est d'utiliser list_objects_v2 avec ContinuationToken pour dépasser la limite de pagination de 1 000 objets.

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'])
1
Behrooz

J'aurais pensé que vous ne pouvez pas avoir de barre oblique dans le nom d'un seau. Vous dites que vous souhaitez répertorier tous les répertoires dans un compartiment, mais votre code tente de répertorier tout le contenu (pas nécessairement les répertoires) dans un certain nombre de compartiments. Ces seaux n'existent probablement pas (car ils ont des noms illégaux). Alors quand tu cours

bucket = s3.Bucket(name)

le compartiment est probablement nul et la liste suivante échouera.

0
Old_Mortality