boto3를 사용하여 s3의 버킷에 키가 있는지 확인하십시오.


164

boto3에 키가 있는지 알고 싶습니다. 버킷 내용을 반복하고 일치하는 경우 키를 확인할 수 있습니다.

그러나 그것은 더 길고 과도한 것으로 보입니다. Boto3 공식 문서에는이를 수행하는 방법이 명시 적으로 나와 있습니다.

나는 명백한 것을 놓치고 있을지도 모른다. 아무도 내가 어떻게 이것을 달성 할 수 있는지 알려 줄 수 있습니까?

답변:


195

Boto 2의 boto.s3.key.Key객체 exists는 HEAD 요청을 수행하고 결과를 확인하여 S3에 키가 있는지 확인 하는 방법을 사용 했지만 더 이상 존재하지 않는 것 같습니다. 당신은 그것을 스스로해야합니다 :

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() 단일 키에 대한 HEAD 요청을 수행합니다. 문제의 객체가 크거나 버킷에 많은 객체가 있어도 빠릅니다.

물론 객체를 사용할 계획이므로 객체가 존재하는지 확인하고있을 수 있습니다. 이 경우에 대해 잊어 버리고 load()a get()또는 download_file()직접 수행 한 다음 오류 사례를 처리하십시오.


빠른 답변 Wander에 감사드립니다. boto3에 대해서도 동일하게 필요합니다.
— Prabhakar Shanmugam 12

12
의 경우 boto3현재 할 수있는 최선의 방법은 전화 head_object하여 키의 메타 데이터를 가져 와서 결과 오류가없는 경우 처리하는 것입니다.
— Wander Nauta

1
@Leonid 당신은 확실히 할 수 있지만, 당신이 할 수있는 함수 나 메소드로 이것을 감싼 경우에만 가능합니다. exists부울이 사라지 도록 예제 코드를 약간 수정했으며 사람들 이이 상황에 맞게해야한다는 것이 더 분명합니다.
— Wander Nauta

2
-1; 나를 위해 작동하지 않습니다. boto3 버전 1.5.26에서는와 e.response['Error']['Code']같은 값이 "NoSuchKey"아닌 것을 알 수 "404"있습니다. 이 답변이 작성된 이후 라이브러리 버전의 차이 또는 API 자체의 변경으로 인한 것인지 여부는 확인하지 않았습니다. 어느 쪽이든, 내 버전의 boto3에서 확인하는 것보다 짧은 접근법 은 처음 e.response['Error']['Code']부터 잡는 것 s3.meta.client.exceptions.NoSuchKey입니다.
— Mark Amery 17

2
s3을 사용하는 경우 client(a와 달리 resource)s3.head_object(Bucket='my_bucket', Key='my_key')s3.Object(...).load()
— user2426679

126

나는 제어 흐름에 예외를 사용하는 것을 좋아하지 않습니다. 이것은 boto3에서 작동하는 대체 방법입니다.

import boto3

s3 = boto3.resource('s3')
bucket = s3.Bucket('my-bucket')
key = 'dootdoot.jpg'
objs = list(bucket.objects.filter(Prefix=key))
if any([w.key == path_s3 for w in objs]):
    print("Exists!")
else:
    print("Doesn't exist")

업데이트 EvilPuppetMaster에 감사드립니다. 불행히도 마지막으로 확인했을 때 목록 버킷 액세스 권한이 없었습니다. 귀하의 답변은 제 질문에 적합하므로 귀하에게 투표했습니다. 그러나 나는 이미 첫 번째 답변을 오래 전에 답변으로 표시했습니다. 당신의 도움을 주셔서 감사합니다.
— Prabhakar Shanmugam

27
이것은 리스팅 요청으로 간주되지 않습니까 (get보다 12.5 배 더 비쌉니다)? 1 억 개의 객체에 대해이 작업을 수행하면 비용이 많이들 수 있습니다 ... 잡기-예외 방법이 불행히도 지금까지 최고라고 생각합니다.
— Pierre D

21
목록은 요청 당 12.5 배나 비쌀 수 있지만 단일 요청은 단일 get이 하나만 반환 할 수있는 1 억 개의 개체를 반환 할 수도 있습니다. 따라서 가상의 경우 목록을 사용하여 1 억 개를 모두 가져온 다음 로컬로 비교하는 것이 100m 개인 가져 오기보다 저렴합니다. 모든 객체에 대해 http 왕복이 필요하지 않기 때문에 1000 배 더 빠르다는 것은 말할 것도 없습니다.
— EvilPuppetMaster

내 파일이 s3 버킷 내의 폴더 안에 있으면 작동하지 않습니다.
— user3186866

2
@ user3186866 S3에는 실제로 "폴더"가 없기 때문입니다. 모든 객체는 주어진 경로에 파일로 존재합니다. 폴더는 스토리지 구조를 구성하고 이해하는 데 도움이되는 도구이지만 실제로는 S3 버킷이 바로 버킷입니다.
— ibtokin

114

내가 찾은 가장 쉬운 방법은 아마도 가장 효율적인 방법입니다.

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

2
참고 : 역할을 사용하거나 .aws 구성에 키가있는 경우 aws_access_key_id / aws_secret_access_key 등을 전달하지 않아도됩니다.s3 = boto3.client('s3')
— Andy Hayden

20
이 테스트를 추가하면 예외를 발생시키는 다른 오류보다는 객체가 실제로 존재하지 않는다는 확신이 조금 더 생깁니다. 'e'는 ClientError 예외 인스턴스입니다.if e.response['ResponseMetadata']['HTTPStatusCode'] == 404:
— Richard

@AndyHayden 각각의 시도는 AWS 비용 측면에서 무엇을 계산합니까?
— 루프

2
@Taylor 요청이 있지만 데이터 전송이 없습니다.
— Andy Hayden

1
ClientError는 404뿐만 아니라 400에 대한 캐치이므로 강력하지 않습니다.
— mickzer

21

Boto3에서 폴더 (접두사) 또는 list_objects를 사용하는 파일을 확인하는 경우 응답 dict에 'Contents'의 존재를 객체의 존재 여부를 확인하는 데 사용할 수 있습니다. @EvilPuppetMaster가 제안한 것처럼 시도 / 제외 캐치를 피하는 또 다른 방법입니다

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

2
이것에 문제가있었습니다. list_objects ( "2000")은 "2000-01", "2000-02"와 같은 키를 반환합니다.
— Gunnar Cheng

3
최대 1000 개의 객체 만 반환합니다! boto3.amazonaws.com/v1/documentation/api/latest/reference/…
— RoachLord

이것은이 같은 가장 효율적인 솔루션이 필요하지 않습니다이다 s3:GetObject권한 만 s3:ListBucket권한을
— Vishrant

11

뿐만 아니라 client하지만 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')

3
객체를 얻고 싶지 않을 수도 있지만 객체가 있는지 확인하십시오. 여기에서 다른 예제와 같이 객체를 향하는 메소드를 사용할 수 있습니다 bucket.Object(key).last_modified.
— ryanjdillon

10

S3F 를 사용할 수 있습니다 . 이는 전형적인 파일 시스템 스타일 작업을 노출시키는 boto3 주위의 래퍼입니다.

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

비록 이것이 효과가 있다고 생각하지만, 질문은 boto3로 이것을하는 방법에 대해 묻습니다. 이 경우 추가 라이브러리를 설치하지 않고 문제를 해결하는 것이 실용적입니다.
— paulkernfeld

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

5

FWIW, 여기 내가 사용하는 매우 간단한 기능이 있습니다.

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
이것은 '파일'과 비교하여 '폴더'의 존재 여부를 확인하는 유일한 응답입니다. 이는 폴더의 특정 파일이 아니라 특정 폴더가 존재하는지 알아야하는 루틴에 매우 중요합니다.
— dave campbell

이것은 신중한 대답이지만이 경우 폴더의 개념이 잘못되었다는 것을 사용자가 이해하는 경우에만 유용합니다. 빈 '폴더'가 버킷 내부의 S3에 존재할 수 있으므로 isdir_s3이 False를 반환하면 몇 분 정도 걸렸습니다. 표현이> 0으로 변경되는 것처럼 답변을 편집하려고 생각했습니다. 당신이 기대하는 결과
— PyNEwbie

5

조용히 덮어 쓰지 않고 키가 있는지 확인하려는 경우 먼저 다음을 확인하십시오.

import boto3

def key_exists(mykey, mybucket):
  s3_client = boto3.client('s3')
  response = s3_client.list_objects_v2(Bucket=mybucket, Prefix=mykey)
  if response:
      for obj in response['Contents']:
          if mykey == obj['Key']:
              return True
  return False

if key_exists('someprefix/myfile-abc123', 'my-bucket-name'):
    print("key exists")
else:
    print("safe to put new bucket object")
    # try:
    #     resp = s3_client.put_object(Body="Your string or file-like object",
    #                                 Bucket=mybucket,Key=mykey)
    # ...check resp success and ClientError exception for errors...

3

이 간단한 시도

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

3

이것은 접두사와 키를 모두 확인하고 최대 1 개의 키를 가져옵니다.

def prefix_exits(bucket, prefix):
    s3_client = boto3.client('s3')
    res = s3_client.list_objects_v2(Bucket=bucket, Prefix=prefix, MaxKeys=1)
    return 'Contents' in res


1
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

1

boto3의 경우, ObjectSummary 를 사용하여 오브젝트가 존재하는지 확인할 수 있습니다.

Amazon S3 버킷에 저장된 객체의 요약을 포함합니다. 이 개체는 개체의 전체 메타 데이터 또는 내용을 포함하지 않습니다.

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

에서 ObjectSummary.load

s3.Client.head_object를 호출하여 ObjectSummary 자원의 속성을 업데이트하십시오.

사용 ObjectSummary하지 Object않을 계획이라면 대신 사용할 수 있음을 나타냅니다 get(). 이 load()함수는 요약 만 얻은 개체를 검색하지 않습니다.


1

다음은 나를 위해 작동하는 솔루션입니다. 한 가지주의 사항은 미리 키의 정확한 형식을 알고 있으므로 단일 파일 만 나열한다는 것입니다.

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."

1

이를 위해 Boto3을 사용할 수 있습니다.

import boto3
s3 = boto3.resource('s3')
bucket = s3.Bucket('my-bucket')
objs = list(bucket.objects.filter(Prefix=key))
if(len(objs)>0):
    print("key exists!!")
else:
    print("key doesn't exist!")

여기서 키는 확인하려는 경로가 존재하는지 여부입니다.


간단한에서 %timeit시험이 가장 빠른 옵션이 보인다
— 이타 마르 카츠

1

get()방법 이 정말 간단합니다

import botocore
from boto3.session import Session
session = Session(aws_access_key_id='AWS_ACCESS_KEY',
                aws_secret_access_key='AWS_SECRET_ACCESS_KEY')
s3 = session.resource('s3')
bucket_s3 = s3.Bucket('bucket_name')

def not_exist(file_key):
    try:
        file_details = bucket_s3.Object(file_key).get()
        # print(file_details) # This line prints the file details
        return False
    except botocore.exceptions.ClientError as e:
        if e.response['Error']['Code'] == "NoSuchKey": # or you can check with e.reponse['HTTPStatusCode'] == '404'
            return True
        return False # For any other error it's hard to determine whether it exists or not. so based on the requirement feel free to change it to True/ False / raise Exception

print(not_exist('hello_world.txt')) 

강력하지는 않지만 HTTP 500과 같은 여러 가지 이유로 예외가 발생할 수
— 있으며이

그러나 파일에 액세스 할 수 있는지 여부에 대한 정보가 필요합니다. 존재하고 액세스 할 수 없으며 존재하지 않는 것과 같습니다. 권리?
— isambitd

@mickzer 지금 변경 사항을 확인하십시오.
— isambitd

1
이전 의견에 답장을 보내려면 아니요, HTTP 500에서의 동작은 401/403을 다시 시도하여 인증 등을 수정하는 것일 수 있습니다. 실제 오류 코드를 확인하는 것이 중요합니다.
— mickzer

0

S3 버킷에 파일이 있는지 여부를 확인할 수있는 간단한 방법이 있습니다. 이를 위해 예외를 사용할 필요는 없습니다.

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

object_name버킷으로 시작하는 파일이있는 경우 올바르지 않습니다 . 예를 들어 my_file.txt.oldversion확인하면 가양 성이 반환됩니다 my_file.txt. 대부분의 경우에 약간의 문제가 있지만 응용 프로그램 전체에서 사용할 가능성이 높은 "파일이 존재합니까?"
— Andrew Schwartz

0

디렉토리와 동등한 키를 찾으려면이 접근법을 원할 수 있습니다

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

이것은 부모 키 또는 파일과 같은 키 또는 존재하지 않는 키에 적용됩니다. 위의 선호하는 방법을 시도했지만 부모 키에서 실패했습니다.


0

나는 예외를 잡기 위해 botocore.exceptions.ClientErrorbotocore를 설치해야한다는 것을 알았습니다. botocore는 36M의 디스크 공간을 차지합니다. aws lambda 함수를 사용하는 경우 특히 영향을 미칩니다. 그 대신 예외를 사용하면 추가 라이브러리 사용을 건너 뛸 수 있습니다!

  • 파일 확장자가 '.csv'인지 확인하고 있습니다.
  • 버킷이 존재하지 않으면 예외가 발생하지 않습니다!
  • 버킷이 있지만 객체가 존재하지 않으면 예외가 발생하지 않습니다!
  • 버킷이 비어 있으면 예외가 발생합니다!
  • 버킷에 권한이없는 경우 예외가 발생합니다!

코드는 다음과 같습니다. 당신의 생각을 공유하십시오 :

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)

AWS는 파이썬 런타임에 boto3가 사전 설치된 상태로 제공된다고 말합니다. docs.aws.amazon.com/lambda/latest/dg/lambda-runtimes.html
— rinat.io

0

스레드를 따라 가면 누군가가 S3에 객체가 있는지 확인하는 가장 효율적인 방법을 결정할 수 있습니까?

head_object는 실제 객체 자체보다 가벼운 메타 데이터를 확인하기 때문에 이길 수 있다고 생각합니다.



-1

체크 아웃

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

버킷 내에 특정 키가 있는지 확인하십시오. 이 메소드는 HEAD 요청을 사용하여 키가 있는지 확인합니다. Key 객체의 인스턴스 또는 None

...에서 BOTO S3 문서

bucket.get_key (keyname)을 호출하고 반환 된 객체가 None인지 확인할 수 있습니다.


OP에 의해 요청 된 boto3에서는 작동하지 않습니다
— MarkNS

AWS boto 라이브러리에는 두 가지 버전이 있습니다. 이 답변은 질문에 의해 요청 된 버전에서는 작동하지 않습니다.
— MarkNS

OP에 대한 정답은 아니지만 boto v2를 사용해야하기 때문에 도움이됩니다. 그래서 나는 부정적인 투표를 철회했습니다.
— haͣrͬukaͣreͤrͬu
당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.