Listado de contenidos de un cubo con boto3

198

¿Cómo puedo ver qué hay dentro de un cubo en S3 boto3? (es decir, hacer un "ls")?

Haciendo lo siguiente:

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

devoluciones:

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

¿Cómo veo su contenido?

Amelio Vazquez-Reina
fuente

Respuestas:

241

Una forma de ver los contenidos sería:

for my_bucket_object in my_bucket.objects.all():
    print(my_bucket_object)
Garnaat
fuente
1
¿Puedo obtener las claves bajo una ruta particular en un cubo o con un delimitador particular usando boto3?
Rahul KP
109
Debería poder decir mybucket.objects.filter(Prefix='foo/bar')y solo enumerará objetos con ese prefijo. También puedes pasar un Delimiterparámetro.
garnaat
3
no funciona con boto3 AttributeError: el objeto 'S3' no tiene atributos 'objetos'
Shek
2
@garnaat Tu comentario mencionando que el método de filtro realmente me ayudó (mi código terminó mucho más simple y rápido) - ¡gracias!
Edward Dixon el
24
Aconsejaría no usar objectcomo nombre de variable, ya que sombreará el tipo global object.
oliland
100

Esto es similar a un 'ls' pero no tiene en cuenta la convención de carpeta de prefijo y enumerará los objetos en el depósito. Le corresponde al lector filtrar los prefijos que forman parte del nombre de la clave.

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

En 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
fuente
39
Si desea utilizar el prefijo también, puede hacerlo así:conn.list_objects(Bucket='bucket_name', Prefix='prefix_string')['Contents']
markonovak
13
Esto solo enumera las primeras 1000 teclas. De la cadena de documentación: "Devuelve algunos o todos (hasta 1000) de los objetos en un cubo". Además, se recomienda que use list_objects_v2 en lugar de list_objects (aunque, esto también solo devuelve las primeras 1000 teclas).
Brett Widmeier
3
Esta limitación debe ser tratada usando Paginators
v25
44

Supongo que ha configurado la autenticación por separado.

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

my_bucket = s3.Bucket('bucket_name')

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

Si desea pasar las teclas ACCESS y SECRET (que no debe hacer, porque no es seguro):

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
fuente
13
Esto es menos seguro que tener un archivo de credenciales en ~ / .aws / credentials. Aunque es una solución válida.
nu everest
66
Esto requeriría comprometer secretos para controlar la fuente. No está bien.
Groth
2
Esta respuesta no agrega nada con respecto a la API / mecánica de enumerar objetos al tiempo que agrega un método de autenticación no relevante que es común para todos los recursos de boto y es una mala práctica de seguridad
Froyke
Se agregó un descargo de responsabilidad a la respuesta sobre seguridad.
rjurney
¿Qué pasaría si las claves fueran suministradas por un sistema de gestión de claves / secreto como Vault (Hashicorp)? ¿No sería eso mejor que simplemente colocar el archivo de credenciales en ~ / .aws / credentials?
SunnyAk
25

Para manejar listados de claves grandes (es decir, cuando la lista del directorio es mayor a 1000 elementos), utilicé el siguiente código para acumular valores clave (es decir, nombres de archivos) con múltiples listados (gracias a Amelio anterior para las primeras líneas). El código es para 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
Hefesto
fuente
20

Mi función de utilidad s3keys es esencialmente una versión optimizada de la respuesta 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']

En mis pruebas (boto3 1.9.84), es significativamente más rápido que el código equivalente (pero más 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))

Como S3 garantiza resultados ordenados binarios UTF-8 , start_afterse ha agregado una optimización a la primera función.

Sean Summers
fuente
Esta es, de lejos, la mejor respuesta. Estaba modificando la respuesta de @ Hephaestus (porque era la más alta) cuando me desplacé hacia abajo. Esta debería ser la respuesta aceptada y debería obtener puntos adicionales por ser conciso. Agregaría que el generador del segundo código necesita ser envuelto list()para devolver una lista de archivos.
Richard D
@RichardD ambos resultados generan generadores. Muchos depósitos a los que apunto con este código tienen más claves de las que la memoria del ejecutor del código puede manejar a la vez (por ejemplo, AWS Lambda); Prefiero consumir las claves a medida que se generan.
Sean Summers el
6

Una manera más parsimoniosa, en lugar de iterar a través de un bucle for, también podría imprimir el objeto original que contiene todos los archivos dentro de su cubo 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
fuente
3
@petezurich, ¿podría explicar por qué una edición tan pequeña de mi respuesta? Reemplazar una "a" con una "A" mayúscula al comienzo de mi respuesta redujo mi reputación por -2, sin embargo, considero que tanto usted como yo estamos de acuerdo que no solo tu corrección NO es relevante en absoluto, sino que es bastante insignificante, ¿no lo dirías? Por favor, enfóquese en el contenido en lugar de las revisiones infantiles, el niño más obligado
Daniel Vieira
Estas fueron dos interacciones diferentes. 1. Edité su respuesta, que se recomienda incluso para errores ortográficos menores. Estoy de acuerdo, que los límites entre menores y triviales son ambiguos. No rechazo ninguna publicación porque veo errores y no lo hice en este caso. Simplemente soluciono todos los errores que veo.
petezurich
2. Desestimé tu respuesta porque escribiste que files_in_s3es un "objeto de lista". No hay tal cosa en Python. Es más bien un iterable y no pude hacer que su código funcione y, por lo tanto, no se votó. Entonces encontré el error y vi su punto, pero no pude deshacer mi voto negativo.
petezurich
55
@petezurich no hay problema, entendí su punto, solo una cosa, en Python, una lista ES un objeto porque casi todo en Python es un objeto, entonces también se deduce que una lista también es iterable, pero ante todo, es un ¡objeto! es por eso que no entendí tu voto negativo: estabas votando algo incorrecto y un código que funciona. De todos modos, gracias por tus disculpas y todo lo mejor
Daniel Vieira
1
@petezurich Todo en Python es un objeto. "Listar objeto" es completamente aceptable.
Zach Garwood
4

ObjectSummary:

Hay dos identificadores que se adjuntan a ObjectSummary:

  • nombre_cubeta
  • llave

boto3 S3: ObjectSummary

Más información sobre las claves de objeto de la documentación de AWS S3:

Claves de objeto:

Cuando crea un objeto, especifica el nombre de la clave, que identifica de forma exclusiva el objeto en el depósito. Por ejemplo, en la consola de Amazon S3 (consulte AWS Management Console), cuando resalta un depósito, aparece una lista de objetos en su depósito. Estos nombres son las claves de objeto. El nombre de una clave es una secuencia de caracteres Unicode cuya codificación UTF-8 tiene una longitud máxima de 1024 bytes.

El modelo de datos de Amazon S3 es una estructura plana: crea un depósito y el depósito almacena objetos. No hay jerarquía de subgrupos o subcarpetas; sin embargo, puede inferir la jerarquía lógica utilizando prefijos y delimitadores de nombres clave como lo hace la consola Amazon S3. La consola de Amazon S3 admite un concepto de carpetas. Suponga que su depósito (creado por el administrador) tiene cuatro objetos con las siguientes claves de objeto:

Desarrollo / Proyectos1.xls

Finanzas / estado de cuenta1.pdf

Private / taxdocument.pdf

s3-dg.pdf

Referencia:

AWS S3: claves de objeto

Aquí hay un código de ejemplo que muestra cómo obtener el nombre del depósito y la clave del objeto.

Ejemplo:

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
fuente
3

Simplemente lo hice así, incluido el método de autenticación:

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
fuente
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
fuente
Ambos "get_s3_keys" devuelven solo la última clave.
Alexey Vazhnov
Sin embargo, esto enumera todos los archivos en el cubo; la pregunta era cómo hacer un ls. ¿Cómo harías eso? Solo imprime los archivos en la raíz
Herman
1

Con una pequeña modificación al código de @Hephaeastus en uno de los comentarios anteriores, escribió el siguiente método para enumerar carpetas y objetos (archivos) en una ruta determinada. Funciona de manera similar 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

Esto enumera todos los objetos / carpetas en una ruta determinada. Folder_path puede dejarse como Ninguno de forma predeterminada y el método enumerará los contenidos inmediatos de la raíz del depósito.

RAM
fuente
0

Aquí esta la solución

importar boto3

s3 = boto3.resource ('s3')

BUCKET_NAME = 'Su nombre del depósito de S3, por ejemplo,' eliminar datos de prueba11 ''

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

para archivo en allFiles: print (file.key)

Shashi Kumar Singh
fuente
0

También se puede hacer de la siguiente manera:

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

Entonces estás pidiendo el equivalente de aws s3 lsen boto3. Esto sería una lista de todas las carpetas y archivos de nivel superior. Esto es lo más cerca que pude llegar; solo enumera todas las carpetas de nivel superior. Sorprendente lo difícil que es una operación tan simple.

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'))
Germán
fuente