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.