Liste du contenu d'un seau avec boto3

198

Comment puis-je voir ce qu'il y a dans un compartiment dans S3 avec boto3? (c'est-à-dire faire un "ls")?

Procédez comme suit:

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

Retour:

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

Comment voir son contenu?

Amelio Vazquez-Reina
la source

Réponses:

244

Une façon de voir le contenu serait:

for my_bucket_object in my_bucket.objects.all():
    print(my_bucket_object)
garnaat
la source
1
puis-je récupérer les clés sous un chemin particulier dans le seau ou avec un délimiteur particulier en utilisant boto3 ??
Rahul KP
110
Vous devriez pouvoir dire mybucket.objects.filter(Prefix='foo/bar')et il ne listera que les objets avec ce préfixe. Vous pouvez également passer un Delimiterparamètre.
garnaat
3
ne fonctionne pas avec boto3 AttributeError: l'objet 'S3' n'a pas d'attribut 'objets'
Shek
2
@garnaat Votre commentaire mentionnant cette méthode de filtrage m'a vraiment aidé (mon code s'est avéré beaucoup plus simple et plus rapide) - merci!
Edward Dixon
24
Je déconseillerais d'utiliser objectcomme nom de variable car il masquera le type global object.
oliland
100

Ceci est similaire à un 'ls' mais il ne prend pas en compte la convention de dossier de préfixe et listera les objets dans le compartiment. Il appartient au lecteur de filtrer les préfixes qui font partie du nom de la clé.

Dans 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)

Dans 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'])
cgseller
la source
39
Si vous souhaitez également utiliser le préfixe, vous pouvez le faire comme ceci:conn.list_objects(Bucket='bucket_name', Prefix='prefix_string')['Contents']
markonovak
14
Cela répertorie uniquement les 1000 premières clés. À partir de la docstring: "Renvoie une partie ou la totalité (jusqu'à 1 000) des objets d'un compartiment." En outre, il est recommandé d'utiliser list_objects_v2 au lieu de list_objects (bien que cela ne renvoie également que les 1000 premières clés).
Brett Widmeier
3
Cette limitation doit être traitée à l'aide de Paginators
v25
44

Je suppose que vous avez configuré l'authentification séparément.

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

my_bucket = s3.Bucket('bucket_name')

for file in my_bucket.objects.all():
    print(file.key)
Tushar Niras
la source
30

Si vous souhaitez passer les clés ACCESS et SECRET (ce que vous ne devez pas faire, car ce n'est pas sécurisé):

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)
Erwin Alberto
la source
13
C'est moins sûr que d'avoir un fichier d'informations d'identification dans ~ / .aws / credentials. Bien que ce soit une solution valable.
nu everest
6
Cela nécessiterait la validation de secrets pour le contrôle de code source. Pas bon.
jan groth
2
Cette réponse n'ajoute rien concernant l'API / la mécanique de la liste des objets tout en ajoutant une méthode d'authentification non pertinente qui est commune à toutes les ressources boto et est une mauvaise pratique en matière de sécurité
Froyke
Ajout d'un avertissement à la réponse sur la sécurité.
rjurney
Et si les clés étaient fournies par un système de gestion de clés / secrets comme Vault (Hashicorp) - ne serait-ce pas mieux que de simplement placer le fichier d'informations d'identification dans ~ / .aws / credentials?
SunnyAk
26

Afin de gérer de grandes listes de clés (c'est-à-dire lorsque la liste de répertoires est supérieure à 1000 éléments), j'ai utilisé le code suivant pour accumuler des valeurs clés (c'est-à-dire des noms de fichiers) avec plusieurs listes (grâce à Amelio ci-dessus pour les premières lignes). Le code est pour 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
Héphaïstos
la source
20

Ma fonction utilitaire s3keys est essentiellement une version optimisée de la réponse de @ 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']

Dans mes tests (boto3 1.9.84), c'est nettement plus rapide que le code équivalent (mais plus simple):

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))

Comme S3 garantit des résultats triés binaires UTF-8 , une start_afteroptimisation a été ajoutée à la première fonction.

Sean Summers
la source
C'est de loin la meilleure réponse. J'étais en train de modifier la réponse de @ Hephaestus (parce que c'était la plus élevée) quand j'ai fait défiler vers le bas. Cela devrait être la réponse acceptée et devrait obtenir des points supplémentaires pour être concise. J'ajouterais que le générateur du deuxième code doit être enveloppé list()pour renvoyer une liste de fichiers.
Richard D
@RichardD les deux résultats renvoient des générateurs. De nombreux buckets que je cible avec ce code ont plus de clés que la mémoire de l'exécuteur de code ne peut gérer à la fois (par exemple, AWS Lambda); Je préfère consommer les clés au fur et à mesure qu'elles sont générées.
Sean Summers
6

De manière plus parcimonieuse, plutôt que d'itérer via une boucle for, vous pouvez également simplement imprimer l'objet d'origine contenant tous les fichiers de votre compartiment 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))
Daniel Vieira
la source
3
@petezurich, pouvez-vous s'il vous plaît expliquer pourquoi une si petite modification de ma réponse - remplacer un «a» par un «A» majuscule au début de ma réponse a fait baisser ma réputation de -2, mais je pense que vous et moi pouvons être d'accord que non seulement votre correction n'est PAS pertinente du tout, mais en fait plutôt insignifiante, n'est-ce pas? Veuillez vous concentrer sur le contenu plutôt que sur les révisions enfantines, le plus obligé ol'boy
Daniel Vieira
Ce sont deux interactions différentes. 1. J'ai modifié votre réponse qui est recommandée même pour les fautes d'orthographe mineures. Je conviens que les frontières entre mineur et trivial sont ambiguës. Je ne déconseille aucun article car je vois des erreurs et je ne l'ai pas fait dans ce cas. Je corrige simplement toutes les erreurs que je vois.
petezurich
2. J'ai décliné votre réponse parce que vous avez écrit que files_in_s3c'est un "objet de liste". Il n'y a rien de tel en Python. C'est plutôt un itérable et je n'ai pas pu faire fonctionner votre code et j'ai donc voté contre. Ensuite, j'ai trouvé l'erreur et vu votre point, mais je n'ai pas pu annuler mon vote défavorable.
petezurich
5
@petezurich pas de problème, j'ai compris votre, point, juste une chose, en Python une liste EST un objet car à peu près tout en python est un objet, alors il s'ensuit également qu'une liste est aussi un itérable, mais d'abord et avant tout, c'est un objet! c'est pourquoi je n'ai pas compris votre vote défavorable - vous étiez en train de voter contre quelque chose qui était correct et un code qui fonctionne. Quoi qu'il en soit, merci pour vos excuses et bonne
chance
1
@petezurich Tout en Python est un objet. "Objet de liste" est tout à fait acceptable.
Zach Garwood le
4

ObjectSummary:

Il existe deux identificateurs attachés à l'ObjectSummary:

  • bucket_name
  • clé

boto3 S3: Résumé de l'objet

En savoir plus sur les clés d'objet de la documentation AWS S3:

Clés d'objet:

Lorsque vous créez un objet, vous spécifiez le nom de la clé, qui identifie de manière unique l'objet dans le compartiment. Par exemple, dans la console Amazon S3 (voir AWS Management Console), lorsque vous mettez un compartiment en surbrillance, une liste d'objets dans votre compartiment s'affiche. Ces noms sont les clés d'objet. Le nom d'une clé est une séquence de caractères Unicode dont le codage UTF-8 a une longueur maximale de 1024 octets.

Le modèle de données Amazon S3 est une structure plate: vous créez un compartiment et le compartiment stocke des objets. Il n'y a pas de hiérarchie de sous-titres ou de sous-dossiers; cependant, vous pouvez déduire une hiérarchie logique à l'aide de préfixes et de délimiteurs de nom de clé comme le fait la console Amazon S3. La console Amazon S3 prend en charge un concept de dossiers. Supposons que votre compartiment (créé par l'administrateur) comporte quatre objets avec les clés d'objet suivantes:

Développement / Projets1.xls

Finance / état1.pdf

Privé / document fiscal.pdf

s3-dg.pdf

Référence:

AWS S3: clés d'objet

Voici un exemple de code qui montre comment obtenir le nom du compartiment et la clé d'objet.

Exemple:

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()
Gothburz
la source
3

Je l'ai juste fait comme ça, y compris la méthode d'authentification:

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
Milean
la source
2
#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)
Imran Selim
la source
Les deux "get_s3_keys" ne retournent que la dernière clé.
Alexey Vazhnov le
Cela répertorie tous les fichiers du bucket; la question était de savoir comment faire un ls. Comment feriez-vous cela ... imprimez uniquement les fichiers à la racine
Herman
1

Avec peu de modifications au code de @Hephaeastus dans l'un des commentaires ci-dessus, a écrit la méthode ci-dessous pour lister les dossiers et les objets (fichiers) dans un chemin donné. Fonctionne de la même manière que la commande 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

Cela répertorie tous les objets / dossiers dans un chemin donné. Folder_path peut être laissé comme None par défaut et la méthode listera le contenu immédiat de la racine du bucket.

RAM
la source
0

Voici la solution

importer boto3

s3 = boto3.resource ('s3')

BUCKET_NAME = 'Votre nom de compartiment S3, par exemple'deletemetesting11' '

allFiles = s3.Bucket (BUCKET_NAME) .objects.all ()

pour le fichier dans allFiles: print (file.key)

Shashi Kumar Singh
la source
0

Vous demandez donc l'équivalent de aws s3 lsin boto3. Ce serait la liste de tous les dossiers et fichiers de niveau supérieur. C'est le plus proche que je puisse obtenir; il répertorie uniquement tous les dossiers de niveau supérieur. Il est surprenant de constater à quel point une opération aussi simple est difficile.

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'))
Herman
la source
0

Voici une fonction simple qui vous renvoie les noms de fichiers de tous les fichiers ou fichiers avec certains types tels que «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
gench
la source
-1

Cela peut également être fait comme suit:

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