web-dev-qa-db-fra.com

vérifier si une clé existe dans un compartiment dans s3 en utilisant boto3

J'aimerais savoir s'il existe une clé dans boto3. Je peux boucler le contenu du seau et vérifier la clé si elle correspond.

Mais cela semble plus long et exagéré. La documentation officielle de Boto3 indique explicitement comment procéder. 

Peut-être que je manque l'évidence. Quelqu'un peut-il me dire comment je peux y arriver?.

86

L’objet boto.s3.key.Key de Boto 2 avait une méthode exists qui vérifiait si la clé existait sur S3 en faisant une requête HEAD et en regardant le résultat, mais il semble que cela n’existe plus. Vous devez le faire vous-même:

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() effectue une demande HEAD pour une clé unique, ce qui est rapide, même si l'objet en question est volumineux ou si vous avez plusieurs objets dans votre compartiment.

Bien sûr, vous pouvez vérifier si l'objet existe parce que vous prévoyez de l'utiliser. Si tel est le cas, vous pouvez simplement oublier la fonction load() et effectuer directement une fonction get() ou download_file(), puis gérer le cas d'erreur à cet endroit.

117
Wander Nauta

Je ne suis pas un grand fan de l'utilisation des exceptions pour le contrôle du flux. C'est une approche alternative qui fonctionne dans 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")
76
EvilPuppetMaster

Le moyen le plus simple que j'ai trouvé (et probablement le plus efficace) est le suivant:

import boto3
from botocore.errorfactory import ClientError

s3 = boto3.client('s3', aws_access_key_id='aws_key', aws_secret_access_key='aws_secret')
try:
    s3.head_object(Bucket='bucket_name', Key='file_path')
except ClientError:
    # Not found
    pass
60
o_c

Dans Boto3, si vous recherchez un dossier (préfixe) ou un fichier utilisant list_objects. Vous pouvez utiliser l'existence de 'Contenu' dans le dict de réponse pour vérifier si l'objet existe ou non. C'est une autre façon d'éviter les tentatives try/except, comme le suggère @EvilPuppetMaster.

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

Non seulement client, mais aussi 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')
10
Vitaly Zdanevich

Essayez ceci 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")
2
Alkesh Mahajan

FWIW, voici les fonctions très simples que j'utilise

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
1
Andy Reagan
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)
1
Vivek

Pour boto3, ObjectSummary peut être utilisé pour vérifier si un objet existe.

Contient le récapitulatif d'un objet stocké dans un compartiment Amazon S3. Cet objet ne contient pas les métadonnées complètes de l'objet, ni aucun de ses contenus.

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

Dans ObjectSummary.load

Appelle s3.Client.head_object pour mettre à jour les attributs de la ressource ObjectSummary.

Cela montre que vous pouvez utiliser ObjectSummary au lieu de Object si vous prévoyez de ne pas utiliser get(). La fonction load() ne récupère pas l'objet, elle obtient uniquement le résumé.

0
Veedka

Si vous avez moins de 1000 dans un répertoire ou un compartiment, vous pouvez en obtenir un et vérifier après si cette clé est dans cet ensemble:

files_in_dir = {d['Key'].split('/')[-1] for d in s3_client.list_objects_v2(
Bucket='mybucket',
Prefix='my/dir').get('Contents') or []}

Ce code fonctionne même si my/dir n'existe pas.

http://boto3.readthedocs.io/en/latest/reference/services/s3.html#S3.Client.list_objects_v2

0
Vitaly Zdanevich

Voici une solution qui fonctionne pour moi. Une mise en garde est que je connais le format exact de la clé à l’avance, je ne fais donc que lister le fichier unique.

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 __== '__main__':
  s3  = S3()
  if s3.check_if_object_exists(bucket, key):
    print "Found S3 object."
  else:
    print "No object found."
0
Rush S

Vous pouvez utiliser S3Fs , qui est essentiellement un wrapper autour de boto3 qui expose les opérations de style de système de fichiers typiques:

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

J'ai remarqué que pour attraper l'exception à l'aide de botocore.exceptions.ClientError, nous devons installer botocore. botocore occupe 36M d’espace disque. Ceci est particulièrement important si nous utilisons les fonctions aws lambda. Au lieu de cela, si nous utilisons simplement une exception, nous pouvons sauter en utilisant la bibliothèque supplémentaire!

  • Je valide pour que l'extension de fichier soit '.csv'
  • Cela ne déclenchera pas d'exception si le compartiment n'existe pas!
  • Cela ne lève pas d'exception si le compartiment existe mais que l'objet n'existe pas!
  • Cela jette une exception si le seau est vide!
  • Cela jette une exception si le compartiment n'a pas de permissions!

Le code ressemble à ceci. S'il vous plaît partager vos pensées:

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)
0
user 923227
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
0
jms

Si vous recherchez une clé équivalente à un répertoire, vous souhaiterez peut-être cette approche.

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

Cela fonctionne pour une clé parent ou une clé qui équivaut à un fichier ou une clé qui n'existe pas. J'ai essayé l'approche privilégiée ci-dessus et j'ai échoué sur les clés parent.

0
Peter Kahn

Il existe un moyen simple de vérifier si le fichier existe ou non dans le compartiment S3. Nous n'avons pas besoin d'utiliser l'exception pour cela

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")
0
Mahesh Mogal