list_objects from example create aws python amazon-s3 boto3

from - python aws sdk



comprobar si existe una clave en un cubo en s3 usando boto3 (17)

Me gustaría saber si existe una clave en boto3. Puedo recorrer el contenido del cubo y verificar la clave si coincide.

Pero eso parece más largo y una exageración. Los documentos oficiales de Boto3 indican explícitamente cómo hacer esto.

Puede ser que me falta lo obvio. ¿Alguien puede señalarme cómo puedo lograr esto?


Aquí hay una solución que me funciona. Una advertencia es que sé el formato exacto de la clave con anticipación, por lo que solo enumero el archivo único

import boto3 # The s3 base class to interact with S3 class S3(object): def __init__(self): self.s3_client = boto3.client(''s3'') def check_if_object_exists(self, s3_bucket, s3_key): response = self.s3_client.list_objects( Bucket = s3_bucket, Prefix = s3_key ) if ''ETag'' in str(response): return True else: return False if __name__ == ''__main__'': s3 = S3() if s3.check_if_object_exists(bucket, key): print "Found S3 object." else: print "No object found."


El objeto boto.s3.key.Key Boto 2 solía tener un método exists que verificaba si la clave existía en S3 haciendo una solicitud HEAD y mirando el resultado, pero parece que ya no existe. Tienes que hacerlo tú mismo:

import boto3 import botocore s3 = boto3.resource(''s3'') try: s3.Object(''my-bucket'', ''dootdoot.jpg'').load() except botocore.exceptions.ClientError as e: if e.response[''Error''][''Code''] == "404": # The object does not exist. ... else: # Something else has gone wrong. raise else: # The object does exist. ...

load() realiza una solicitud HEAD para una sola clave, que es rápida, incluso si el objeto en cuestión es grande o tiene muchos objetos en su depósito.

Por supuesto, es posible que esté verificando si el objeto existe porque planea usarlo. Si ese es el caso, puede olvidarse de la load() y hacer un get() o download_file() directamente, luego maneje el caso de error allí.


En Boto3, si está buscando una carpeta (prefijo) o un archivo usando list_objects. Puede usar la existencia de ''Contenido'' en el dict de respuesta como una verificación de si el objeto existe. Es otra forma de evitar el intento / excepto las capturas como sugiere @EvilPuppetMaster

import boto3 client = boto3.client(''s3'') results = client.list_objects(Bucket=''my-bucket'', Prefix=''dootdoot.jpg'') return ''Contents'' in results


FWIW, aquí están las funciones muy simples que estoy usando

import boto3 def get_resource(config: dict={}): """Loads the s3 resource. Expects AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY to be in the environment or in a config dictionary. Looks in the environment first.""" s3 = boto3.resource(''s3'', aws_access_key_id=os.environ.get( "AWS_ACCESS_KEY_ID", config.get("AWS_ACCESS_KEY_ID")), aws_secret_access_key=os.environ.get("AWS_SECRET_ACCESS_KEY", config.get("AWS_SECRET_ACCESS_KEY"))) return s3 def get_bucket(s3, s3_uri: str): """Get the bucket from the resource. A thin wrapper, use with caution. Example usage: >> bucket = get_bucket(get_resource(), s3_uri_prod)""" return s3.Bucket(s3_uri) def isfile_s3(bucket, key: str) -> bool: """Returns T/F whether the file exists.""" objs = list(bucket.objects.filter(Prefix=key)) return len(objs) == 1 and objs[0].key == key def isdir_s3(bucket, key: str) -> bool: """Returns T/F whether the directory exists.""" objs = list(bucket.objects.filter(Prefix=key)) return len(objs) > 1


Hay una manera simple por la cual podemos verificar si el archivo existe o no en el depósito S3. No necesitamos usar una excepción para esto

sesssion = boto3.Session(aws_access_key_id, aws_secret_access_key) s3 = session.client(''s3'') object_name = ''filename'' bucket = ''bucketname'' obj_status = s3.list_objects(Bucket = bucket, Prefix = object_name) if obj_status.get(''Contents''): print("File exists") else: print("File does not exists")


La forma más fácil que encontré (y probablemente la más eficiente) es esta:

import boto3 from botocore.errorfactory import ClientError s3 = boto3.client(''s3'') try: s3.head_object(Bucket=''bucket_name'', Key=''file_path'') except ClientError: # Not found pass


No solo client sino también bucket :

import boto3 import botocore bucket = boto3.resource(''s3'', region_name=''eu-west-1'').Bucket(''my-bucket'') try: bucket.Object(''my-file'').get() except botocore.exceptions.ClientError as ex: if ex.response[''Error''][''Code''] == ''NoSuchKey'': print(''NoSuchKey'')


No soy un gran fanático del uso de excepciones para el flujo de control. Este es un enfoque alternativo que funciona en boto3:

import boto3 s3 = boto3.resource(''s3'') bucket = s3.Bucket(''my-bucket'') key = ''dootdoot.jpg'' objs = list(bucket.objects.filter(Prefix=key)) if len(objs) > 0 and objs[0].key == key: print("Exists!") else: print("Doesn''t exist")


Noté que solo para detectar la excepción usando botocore.exceptions.ClientError necesitamos instalar botocore. botocore ocupa 36 millones de espacio en disco. Esto es particularmente impactante si usamos funciones aws lambda. En lugar de eso, si solo usamos la excepción, ¡podemos omitir el uso de la biblioteca adicional!

  • Estoy validando que la extensión del archivo sea ''.csv''
  • ¡Esto no arrojará una excepción si el cubo no existe!
  • ¡Esto no arrojará una excepción si el depósito existe pero el objeto no existe!
  • ¡Esto arroja una excepción si el cubo está vacío!
  • ¡Esto arroja una excepción si el cubo no tiene permisos!

El código se ve así. Por favor comparte tus pensamientos:

import boto3 import traceback def download4mS3(s3bucket, s3Path, localPath): s3 = boto3.resource(''s3'') print(''Looking for the csv data file ending with .csv in bucket: '' + s3bucket + '' path: '' + s3Path) if s3Path.endswith(''.csv'') and s3Path != '''': try: s3.Bucket(s3bucket).download_file(s3Path, localPath) except Exception as e: print(e) print(traceback.format_exc()) if e.response[''Error''][''Code''] == "404": print("Downloading the file from: [", s3Path, "] failed") exit(12) else: raise print("Downloading the file from: [", s3Path, "] succeeded") else: print("csv file not found in in : [", s3Path, "]") exit(12)


Para boto3, ObjectSummary se puede usar para verificar si existe un objeto.

Contiene el resumen de un objeto almacenado en un bucket de Amazon S3. Este objeto no contiene los metadatos completos del objeto ni ninguno de sus contenidos.

import boto3 from botocore.errorfactory import ClientError def path_exists(path, bucket_name): """Check to see if an object exists on S3""" s3 = boto3.resource(''s3'') try: s3.ObjectSummary(bucket_name=bucket_name, key=path).load() except ClientError as e: if e.response[''Error''][''Code''] == "404": return False else: raise e return True path_exists(''path/to/file.html'')

En ObjectSummary.load

Llama a s3.Client.head_object para actualizar los atributos del recurso ObjectSummary.

Esto muestra que puede usar ObjectSummary lugar de Object si planea no usar get() . La función load() no recupera el objeto, solo obtiene el resumen.


Prueba esto simple

import boto3 s3 = boto3.resource(''s3'') bucket = s3.Bucket(''mybucket_name'') # just Bucket name file_name = ''A/B/filename.txt'' # full file path obj = list(bucket.objects.filter(Prefix=file_name)) if len(obj) > 0: print("Exists") else: print("Not Exists")


Puede usar S3Fs , que es esencialmente un contenedor alrededor de boto3 que expone las operaciones típicas de estilo de sistema de archivos:

import s3fs s3 = s3fs.S3FileSystem() s3.exists(''myfile.txt'')


Revisa

bucket.get_key( key_name, headers=None, version_id=None, response_headers=None, validate=True )

Verifique si existe una clave en particular dentro del cubo. Este método utiliza una solicitud HEAD para verificar la existencia de la clave. Devuelve: una instancia de un objeto clave o ninguno

de Boto S3 Docs

Simplemente puede llamar a bucket.get_key (keyname) y verificar si el objeto devuelto es None.


Si busca una clave que sea equivalente a un directorio, es posible que desee este enfoque

session = boto3.session.Session() resource = session.resource("s3") bucket = resource.Bucket(''mybucket'') key = ''dir-like-or-file-like-key'' objects = [o for o in bucket.objects.filter(Prefix=key).limit(1)] has_key = len(objects) > 0

Esto funciona para una clave principal o una clave que equivale a un archivo o una clave que no existe. Probé el enfoque favorito anterior y fallé en las claves principales.



import boto3 client = boto3.client(''s3'') s3_key = ''Your file without bucket name e.g. abc/bcd.txt'' bucket = ''your bucket name'' content = client.head_object(Bucket=bucket,Key=s3_key) if content.get(''ResponseMetadata'',None) is not None: print "File exists - s3://%s/%s " %(bucket,s3_key) else: print "File does not exist - s3://%s/%s " %(bucket,s3_key)


S3_REGION="eu-central-1" bucket="mybucket1" name="objectname" import boto3 from botocore.client import Config client = boto3.client(''s3'',region_name=S3_REGION,config=Config(signature_version=''s3v4'')) list = client.list_objects_v2(Bucket=bucket,Prefix=name) for obj in list.get(''Contents'', []): if obj[''Key''] == name: return True return False