Elenco dei contenuti di un bucket con boto3


198

Come posso vedere cosa c'è dentro un bucket in S3 con boto3? (cioè fare un "ls")?

Procedere come segue:

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

ritorna:

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

Come vedo il suo contenuto?

Risposte:


244

Un modo per vedere i contenuti sarebbe:

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

1
posso recuperare le chiavi in ​​un determinato percorso nel bucket o con un delimitatore particolare usando boto3 ??
Rahul KP,

110
Dovresti essere in grado di dire mybucket.objects.filter(Prefix='foo/bar')e elencherà solo gli oggetti con quel prefisso. Puoi anche passare un Delimiterparametro.
Garnaat,

3
non funziona con boto3 AttributeError: l'oggetto 'S3' non ha attributo 'oggetti'
Shek

2
@garnaat Il tuo commento menzionando che il metodo di filtro mi ha davvero aiutato (il mio codice è diventato molto più semplice e veloce) - grazie!
Edward Dixon,

24
Vorrei sconsigliare l'utilizzo objectcome nome variabile in quanto oscurerà il tipo globale object.
oliland

100

Questo è simile a 'ls' ma non tiene conto della convenzione delle cartelle dei prefissi e elencherà gli oggetti nel bucket. Spetta al lettore filtrare i prefissi che fanno parte del nome della chiave.

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

In 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'])

39
Se vuoi usare anche il prefisso, puoi farlo in questo modo:conn.list_objects(Bucket='bucket_name', Prefix='prefix_string')['Contents']
markonovak

14
Questo elenca solo le prime 1000 chiavi. Dal docstring: "Restituisce alcuni o tutti (fino a 1000) degli oggetti in un secchio." Inoltre, si consiglia di utilizzare list_objects_v2 invece di list_objects (sebbene ciò restituisca solo le prime 1000 chiavi).
Brett Widmeier,

3
Questa limitazione dovrebbe essere trattata usando i paginatori
v25

44

Suppongo che tu abbia configurato l'autenticazione separatamente.

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

my_bucket = s3.Bucket('bucket_name')

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

30

Se vuoi passare le chiavi ACCESS e SECRET (cosa che non dovresti fare, perché non è sicura):

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)

13
Questo è meno sicuro di avere un file di credenziali in ~ / .aws / credentials. Sebbene sia una soluzione valida.
Nu Everest,

6
Ciò richiederebbe commettere segreti per il controllo del codice sorgente. Non bene.
Jan Groth,

2
Questa risposta non aggiunge nulla per quanto riguarda l'API / la meccanica di elencare gli oggetti mentre si aggiunge un metodo di autenticazione non rilevante che è comune per tutte le risorse di boto ed è una cattiva pratica per quanto riguarda la sicurezza
Froyke,

Aggiunto un disclaimer alla risposta sulla sicurezza.
rjurney,

E se le chiavi fossero fornite dal sistema di gestione delle chiavi / segrete come Vault (Hashicorp) - non sarebbe meglio che posizionare semplicemente il file delle credenziali in ~ / .aws / credentials?
SunnyAk,

26

Al fine di gestire elenchi di chiavi di grandi dimensioni (ovvero quando l'elenco di directory è maggiore di 1000 articoli), ho usato il codice seguente per accumulare valori chiave (cioè nomi di file) con più elenchi (grazie a Amelio sopra per le prime righe). Il codice è per 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

20

La mia funzione di utilità s3keys è essenzialmente una versione ottimizzata della risposta di @Efesto:

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']

Nei miei test (boto3 1.9.84), è significativamente più veloce del codice equivalente (ma più semplice):

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

Poiché S3 garantisce risultati ordinati binari UTF-8 , start_afterè stata aggiunta un'ottimizzazione alla prima funzione.


Questa è di gran lunga la risposta migliore. Stavo solo modificando la risposta di @Efesto (perché era la più alta) quando ho scorrere verso il basso. Questa dovrebbe essere la risposta accettata e dovrebbe ottenere punti extra per essere concisa. Vorrei aggiungere che il generatore del secondo codice deve essere racchiuso list()per restituire un elenco di file.
Richard D,

@RichardD entrambi i risultati restituiscono generatori. Molti bucket che scelgo come target con questo codice hanno più chiavi di quelle che la memoria dell'esecutore del codice può gestire contemporaneamente (ad es. AWS Lambda); Preferisco consumare le chiavi quando vengono generate.
Sean Summers,

6

Un modo più parsimonioso, piuttosto che scorrere attraverso un ciclo for, potresti anche semplicemente stampare l'oggetto originale contenente tutti i file all'interno del tuo bucket 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))

3
@petezurich, puoi spiegare perché una modifica così modesta della mia risposta - la sostituzione di una "a" con una "A" maiuscola all'inizio della mia risposta ha fatto diminuire la mia reputazione di -2, tuttavia, ritengo che sia io che te possiamo essere d'accordo che non solo la tua correzione NON è affatto rilevante, ma in realtà è piuttosto meschina, non lo diresti? Si prega di concentrarsi sul contenuto piuttosto che su revisioni infantili, ol'boy più obbligato
Daniel Vieira,

Queste erano due diverse interazioni. 1. Ho modificato la tua risposta che è consigliata anche per errori di ortografia minori. Concordo sul fatto che i confini tra minore e banale sono ambigui. Non declassare alcun post perché vedo errori e in questo caso non l'ho fatto. Semplicemente correggo tutti gli errori che vedo.
petezurich,

2. Ho votato in negativo la tua risposta perché hai scritto che files_in_s3è un "oggetto elenco". Non esiste nulla di simile in Python. Piuttosto è un iterabile e non ho potuto far funzionare il tuo codice e quindi ridimensionato. Poi ho trovato l'errore e ho visto il tuo punto ma non ho potuto annullare il mio downvote.
petezurich,

5
@petezurich nessun problema, capito, punto, solo una cosa, in Python una lista È un oggetto perché praticamente tutto in Python è un oggetto, quindi ne consegue anche che una lista è anche un iterabile, ma prima di tutto, è un oggetto! ecco perché non ho capito il tuo downvote, hai votato male qualcosa che era corretto e il codice che funziona. Comunque, grazie per le tue scuse e tutto il meglio
Daniel Vieira,

1
@petezurich Tutto in Python è un oggetto. "Elenco oggetti" è completamente accettabile.
Zach Garwood,

4

ObjectSummary:

Esistono due identificatori collegati a ObjectSummary:

  • bucket_name
  • chiave

boto3 S3: ObjectSummary

Ulteriori informazioni sulle chiavi dell'oggetto dalla documentazione di AWS S3:

Chiavi oggetto:

Quando si crea un oggetto, si specifica il nome della chiave, che identifica in modo univoco l'oggetto nel bucket. Ad esempio, nella console Amazon S3 (vedi AWS Management Console), quando si evidenzia un bucket, viene visualizzato un elenco di oggetti nel bucket. Questi nomi sono le chiavi dell'oggetto. Il nome di una chiave è una sequenza di caratteri Unicode la cui codifica UTF-8 è lunga al massimo 1024 byte.

Il modello di dati Amazon S3 è una struttura piatta: si crea un bucket e il bucket archivia gli oggetti. Non esiste una gerarchia di sotto-cartelle o sottocartelle; tuttavia, puoi inferire la gerarchia logica usando prefissi e delimitatori di nomi di chiavi come fa la console Amazon S3. La console Amazon S3 supporta un concetto di cartelle. Supponiamo che il bucket (creato dall'amministratore) abbia quattro oggetti con le seguenti chiavi oggetto:

Sviluppo / Projects1.xls

Finanza / statement1.pdf

Privato / taxdocument.pdf

s3-dg.pdf

Riferimento:

AWS S3: chiavi dell'oggetto

Ecco un esempio di codice che dimostra come ottenere il nome del bucket e la chiave dell'oggetto.

Esempio:

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

3

L'ho fatto così, incluso il metodo di autenticazione:

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

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)

Entrambi "get_s3_keys" restituisce solo l'ultima chiave.
Alexey Vazhnov,

Questo elenca però tutti i file nel bucket; la domanda era come fare un ls. Come faresti ... stampare solo i file nella radice
Herman,

1

Con poche modifiche al codice di @Hephaeastus in uno dei commenti sopra, ha scritto il metodo seguente per elencare cartelle e oggetti (file) in un determinato percorso. Funziona in modo simile al comando 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

Questo elenca tutti gli oggetti / cartelle in un determinato percorso. Cartella_percorso può essere lasciato come Nessuno per impostazione predefinita e il metodo elencherà i contenuti immediati della radice del bucket.


0

Ecco la soluzione

import boto3

s3 = boto3.resource ('s3')

BUCKET_NAME = 'Il tuo nome di bucket S3 ad es.

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

per file in allFiles: print (file.key)


0

Quindi stai chiedendo l'equivalente di aws s3 lsin boto3. Questo dovrebbe elencare tutte le cartelle e i file di livello superiore. Questo è il più vicino che potrei ottenere; elenca solo tutte le cartelle di livello superiore. Sorprendente quanto sia difficile un'operazione così semplice.

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

0

Ecco una semplice funzione che ti restituisce i nomi di file di tutti i file o file con determinati tipi come '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

-1

Può anche essere fatto come segue:

csv_files = s3.list_objects_v2(s3_bucket_path)
    for obj in csv_files['Contents']:
        key = obj['Key']
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.