python - example - Recuperando nombres de subcarpetas en el depósito S3 de boto3
python s3 bucket (7)
La pieza debajo del código devuelve SOLAMENTE las ''subcarpetas'' en una ''carpeta'' del cubo s3.
import boto3
bucket = ''my-bucket''
#Make sure you provide / in the end
prefix = ''prefix-name-with-slash/''
client = boto3.client(''s3'')
result = client.list_objects(Bucket=bucket, Prefix=prefix, Delimiter=''/'')
for o in result.get(''CommonPrefixes''):
print ''sub folder : '', o.get(''Prefix'')
Para más detalles, puede consultar https://github.com/boto/boto3/issues/134
Utilizando boto3, puedo acceder a mi cubo AWS S3:
s3 = boto3.resource(''s3'')
bucket = s3.Bucket(''my-bucket-name'')
Ahora, el depósito contiene la carpeta de first-level
, que a su vez contiene varias subcarpetas nombradas con una marca de tiempo, por ejemplo 1456753904534
. Necesito saber el nombre de estas subcarpetas para otro trabajo que estoy haciendo y me pregunto si podría hacer que boto3 las recupere.
Así que lo intenté:
objs = bucket.meta.client.list_objects(Bucket=''my-bucket-name'')
que da un diccionario, cuya clave "Contenido" me da todos los archivos de tercer nivel en lugar de los directorios de marca de tiempo de segundo nivel; de hecho, recibo una lista que contiene cosas como
{u''ETag '':'' "etag" '', u''Key'': primer nivel / 1456753904534 / part-00014 '', u''LastModified'': datetime.datetime (2016, 2, 29, 13, 52, 24, tzinfo = tzutc ()),
u''Owner '': {u''DisplayName'': ''propietario'', u''ID '':'' id ''},
u''Size '': size, u''StorageClass'': ''storageclass''}
Puede ver que se recuperan los archivos específicos, en este caso part-00014
, mientras que me gustaría obtener el nombre del directorio solo. En principio, podría quitar el nombre del directorio de todas las rutas, ¡pero es feo y costoso recuperar todo en el tercer nivel para obtener el segundo nivel!
También intenté algo reportado aquí :
for o in bucket.objects.filter(Delimiter=''/''):
print(o.key)
pero no obtengo las carpetas en el nivel deseado.
¿Hay una manera de resolver esto?
S3 es un almacenamiento de objetos, no tiene una estructura de directorios real. El "/" es bastante cosmético. Una de las razones por las que las personas desean tener una estructura de directorio es porque pueden mantener / podar / agregar un árbol a la aplicación. Para S3, usted trata dicha estructura como un tipo de índice o etiqueta de búsqueda.
Para manipular objetos en S3, necesita boto3.client o boto3.resource, por ejemplo, para listar todos los objetos
import boto3
s3 = boto3.client("s3")
all_objects = s3.list_objects(Bucket = ''my-bucket-name'')
http://boto3.readthedocs.org/en/latest/reference/services/s3.html#S3.Client.list_objects
Un recordatorio sobre boto3: boto3.resource es una buena API de alto nivel. Hay pros y contras usando boto3.client vs boto3.resource. Si desarrolla una biblioteca compartida interna, el uso de boto3.resource le dará una capa de blackbox sobre los recursos utilizados.
En primer lugar, no existe un concepto de carpeta real en S3. Definitivamente puede tener un archivo @ ''/folder/subfolder/myfile.txt''
y ninguna carpeta ni subcarpeta.
Para "simular" una carpeta en S3, debe crear un archivo vacío con un ''/'' al final de su nombre (consulte el boto de Amazon S3: ¿cómo crear una carpeta? )
Para su problema, probablemente debería usar el método get_all_keys
con los 2 parámetros: prefix
y delimiter
https://github.com/boto/boto/blob/develop/boto/s3/bucket.py#L427
for key in bucket.get_all_keys(prefix=''first-level/'', delimiter=''/''):
print(key.name)
La última documentación de BOTO3 ahora recomienda usar list_objects_v2 http://boto3.readthedocs.io/en/latest/reference/services/s3.html#S3.Client.list_objects_v2
Me tomó mucho tiempo averiguarlo, pero finalmente aquí hay una manera simple de mostrar los contenidos de una subcarpeta en el cubo S3 usando boto3. Espero eso ayude
prefix = "folderone/foldertwo/"
s3 = boto3.resource(''s3'')
bucket = s3.Bucket(name="bucket_name_here")
FilesNotFound = True
for obj in bucket.objects.filter(Prefix=prefix):
print(''{0}:{1}''.format(bucket.name, obj.key))
FilesNotFound = False
if FilesNotFound:
print("ALERT", "No file in {0}/{1}".format(bucket, prefix))
El AWS cli hace esto (presumiblemente sin buscar e iterar a través de todas las claves en el cubo) cuando ejecuta aws s3 ls s3://my-bucket/
, así que pensé que debe haber una forma de usar boto3.
Parece que de hecho usan Prefix y Delimiter: pude escribir una función que me proporcionaría todos los directorios en el nivel raíz de un segmento modificando un poco ese código:
def list_folders_in_bucket(bucket):
paginator = boto3.client(''s3'').get_paginator(''list_objects'')
folders = []
iterator = paginator.paginate(Bucket=bucket, Prefix='''', Delimiter=''/'', PaginationConfig={''PageSize'': None})
for response_data in iterator:
prefixes = response_data.get(''CommonPrefixes'', [])
for prefix in prefixes:
prefix_name = prefix[''Prefix'']
if prefix_name.endswith(''/''):
folders.append(prefix_name.rstrip(''/''))
return folders
Lo siguiente funciona para mí ... Objetos S3:
s3://bucket/
form1/
section11/
file111
file112
section12/
file121
form2/
section21/
file211
file112
section22/
file221
file222
...
...
...
Utilizando:
from boto3.session import Session
s3client = session.client(''s3'')
resp = s3client.list_objects(Bucket=bucket, Prefix='''', Delimiter="/")
forms = [x[''Prefix''] for x in resp[''CommonPrefixes'']]
obtenemos:
form1/
form2/
...
Con:
resp = s3client.list_objects(Bucket=bucket, Prefix=''form1/'', Delimiter="/")
sections = [x[''Prefix''] for x in resp[''CommonPrefixes'']]
obtenemos:
form1/section11/
form1/section12/