programing

S3 버킷의 하위 폴더 이름을 bo에서 3으로 검색하는 중

bestprogram 2023. 6. 6. 10:22

S3 버킷의 하위 폴더 이름을 bo에서 3으로 검색하는 중

boto3를 사용하여 AWS S3 버킷에 액세스할 수 있습니다.

s3 = boto3.resource('s3')
bucket = s3.Bucket('my-bucket-name')

이제 버킷에 폴더가 포함되어 있습니다.first-level예를 들어 타임스탬프로 이름이 지정된 여러 하위 폴더가 포함되어 있습니다.1456753904534제가 하고 있는 다른 작업을 위해 이 하위 폴더의 이름을 알아야 하는데 bto3에서 검색할 수 있었는지 궁금합니다.

그래서 노력했습니다.

objs = bucket.meta.client.list_objects(Bucket='my-bucket-name')

사전을 제공합니다. 사전 키의 '내용'은 2단계 타임스탬프 디렉토리 대신 모든 3단계 파일을 제공합니다. 사실 저는 다음과 같은 것들을 포함하는 목록을 얻습니다.

{u'ETAG': 'etag', 'u'Key': 1단계/1456753904534/part-00014', u'LastModified': datetime.datetime(2016, 2, 29, 13, 52, 24, tzinfo=tzutc),
u'owner': {u'DisplayName': 'owner', u'ID': 'id',
u'Size': size, u'StorageClass': 'storageclass'}

이 경우 특정 파일을 볼 수 있습니다.part-00014디렉토리의 이름을 단독으로 얻고 싶습니다.원칙적으로 모든 경로에서 디렉터리 이름을 제거할 수 있지만 세 번째 레벨에서 두 번째 레벨을 얻기 위해 모든 것을 검색하는 것은 추악하고 비용이 많이 듭니다!

여기에 보고된 내용도 시도해 보았습니다.

for o in bucket.objects.filter(Delimiter='/'):
    print(o.key)

원하는 수준의 폴더가 없습니다.

이것을 해결할 방법이 있습니까?

아래 코드 조각은 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')

자세한 내용은 https://github.com/boto/boto3/issues/134 를 참조하십시오.

S3는 객체 스토리지이며 실제 디렉터리 구조를 가지고 있지 않습니다."/"는 다소 겉치레적입니다.응용프로그램에 트리를 유지/제거/추가할 수 있기 때문에 사람들이 디렉토리 구조를 갖고 싶어하는 이유 중 하나입니다.S3의 경우 이러한 구조를 인덱스 또는 검색 태그의 일종으로 처리합니다.

S3에서 객체를 조작하려면 boto3.client 또는 boto3.resource가 필요합니다.모든 개체를 나열하려면

import boto3 
s3 = boto3.client("s3")
all_objects = s3.list_objects(Bucket = 'bucket-name') 

http://boto3.readthedocs.org/en/latest/reference/services/s3.html#S3.Client.list_objects

실제로 s3 개체 이름이 '/' 구분 기호를 사용하여 저장된 경우.list_objects(list_objects_v2)의 최신 버전을 사용하면 지정된 접두사로 시작하는 키로 응답을 제한할 수 있습니다.

특정 하위 폴더 아래의 항목으로 항목을 제한하려면 다음과 같이 하십시오.

    import boto3 
    s3 = boto3.client("s3")
    response = s3.list_objects_v2(
            Bucket=BUCKET,
            Prefix ='DIR1/DIR2',
            MaxKeys=100 )

문서화

또 다른 옵션은 python os.path 함수를 사용하여 폴더 접두사를 추출하는 것입니다.문제는 이 작업을 수행하려면 원하지 않는 디렉토리의 개체를 나열해야 합니다.

import os
s3_key = 'first-level/1456753904534/part-00014'
filename = os.path.basename(s3_key) 
foldername = os.path.dirname(s3_key)

# if you are not using conventional delimiter like '#' 
s3_key = 'first-level#1456753904534#part-00014'
filename = s3_key.split("#")[-1]

boto3:boto3.resource에 대한 알림은 고급 API입니다.boto3.client와 boto3.resource를 사용하는 것에는 장단점이 있습니다.내부 공유 라이브러리를 개발하는 경우 boto3.resource를 사용하면 사용된 리소스 위에 블랙박스 계층이 제공됩니다.

단답:

  • 사용합니다. 이렇게 하면 버킷을 반복적으로 나열할 수 없습니다.여기서 일부 답변은 전체 목록을 작성하고 일부 문자열 조작을 사용하여 디렉터리 이름을 검색하는 것을 잘못 제안합니다.이것은 끔찍하게 비효율적일 수 있습니다.S3에는 버킷에 포함할 수 있는 개체 수에 대한 제한이 거의 없습니다.그래서, 상상해보세요, 그 사이에.bar/그리고.foo/당신은 1조 개의 물체를 가지고 있습니다: 당신은 얻기 위해 매우 오랜 시간을 기다릴 것입니다.['bar/', 'foo/'].

  • 사용합니다. 동일한 이유로 (S3는 엔지니어의 무한대 근사치) 페이지를 모두 나열하고 모든 목록을 메모리에 저장하지 않도록 해야 합니다.대신 "리스터"를 반복기로 간주하고 생성되는 스트림을 처리합니다.

  • 사용하지 않습니다.resource버전은 잘 처리되지 않는 것 같습니다.Delimiter선택.리소스가 있으면 다음과 같이 말합니다.bucket = boto3.resource('s3').Bucket(name) 수 있습니다.bucket.meta.client.

답변:

다음은 단순 버킷(버전 처리 없음)에 사용하는 반복기입니다.

import os
import boto3
from collections import namedtuple
from operator import attrgetter


S3Obj = namedtuple('S3Obj', ['key', 'mtime', 'size', 'ETag'])


def s3list(bucket, path, start=None, end=None, recursive=True, list_dirs=True,
           list_objs=True, limit=None):
    """
    Iterator that lists a bucket's objects under path, (optionally) starting with
    start and ending before end.

    If recursive is False, then list only the "depth=0" items (dirs and objects).

    If recursive is True, then list recursively all objects (no dirs).

    Args:
        bucket:
            a boto3.resource('s3').Bucket().
        path:
            a directory in the bucket.
        start:
            optional: start key, inclusive (may be a relative path under path, or
            absolute in the bucket)
        end:
            optional: stop key, exclusive (may be a relative path under path, or
            absolute in the bucket)
        recursive:
            optional, default True. If True, lists only objects. If False, lists
            only depth 0 "directories" and objects.
        list_dirs:
            optional, default True. Has no effect in recursive listing. On
            non-recursive listing, if False, then directories are omitted.
        list_objs:
            optional, default True. If False, then directories are omitted.
        limit:
            optional. If specified, then lists at most this many items.

    Returns:
        an iterator of S3Obj.

    Examples:
        # set up
        >>> s3 = boto3.resource('s3')
        ... bucket = s3.Bucket('bucket-name')

        # iterate through all S3 objects under some dir
        >>> for p in s3list(bucket, 'some/dir'):
        ...     print(p)

        # iterate through up to 20 S3 objects under some dir, starting with foo_0010
        >>> for p in s3list(bucket, 'some/dir', limit=20, start='foo_0010'):
        ...     print(p)

        # non-recursive listing under some dir:
        >>> for p in s3list(bucket, 'some/dir', recursive=False):
        ...     print(p)

        # non-recursive listing under some dir, listing only dirs:
        >>> for p in s3list(bucket, 'some/dir', recursive=False, list_objs=False):
        ...     print(p)
"""
    kwargs = dict()
    if start is not None:
        if not start.startswith(path):
            start = os.path.join(path, start)
        # note: need to use a string just smaller than start, because
        # the list_object API specifies that start is excluded (the first
        # result is *after* start).
        kwargs.update(Marker=__prev_str(start))
    if end is not None:
        if not end.startswith(path):
            end = os.path.join(path, end)
    if not recursive:
        kwargs.update(Delimiter='/')
        if not path.endswith('/'):
            path += '/'
    kwargs.update(Prefix=path)
    if limit is not None:
        kwargs.update(PaginationConfig={'MaxItems': limit})

    paginator = bucket.meta.client.get_paginator('list_objects')
    for resp in paginator.paginate(Bucket=bucket.name, **kwargs):
        q = []
        if 'CommonPrefixes' in resp and list_dirs:
            q = [S3Obj(f['Prefix'], None, None, None) for f in resp['CommonPrefixes']]
        if 'Contents' in resp and list_objs:
            q += [S3Obj(f['Key'], f['LastModified'], f['Size'], f['ETag']) for f in resp['Contents']]
        # note: even with sorted lists, it is faster to sort(a+b)
        # than heapq.merge(a, b) at least up to 10K elements in each list
        q = sorted(q, key=attrgetter('key'))
        if limit is not None:
            q = q[:limit]
            limit -= len(q)
        for p in q:
            if end is not None and p.key >= end:
                return
            yield p


def __prev_str(s):
    if len(s) == 0:
        return s
    s, c = s[:-1], ord(s[-1])
    if c > 0:
        s += chr(c - 1)
    s += ''.join(['\u7FFF' for _ in range(10)])
    return s

테스트:

은 다은시동테데됩다니도이움는의 하는 데 .paginator그리고.list_objects여러 개의 dir 및 파일을 생성합니다.페이지가 최대 1000개의 항목이기 때문에 여러 개의 항목을 dir 및 파일에 사용합니다. dirs에는 디렉터리만 포함되어 있습니다(각각 개체가 하나씩 있음). mixed에는 dir와 객체가 혼합되어 있으며, 각 dir에 대해 2개의 객체 비율이 있습니다(물론 dir 아래에 하나의 객체가 있습니다. S3에는 객체만 저장됨).

import concurrent
def genkeys(top='tmp/test', n=2000):
    for k in range(n):
        if k % 100 == 0:
            print(k)
        for name in [
            os.path.join(top, 'dirs', f'{k:04d}_dir', 'foo'),
            os.path.join(top, 'mixed', f'{k:04d}_dir', 'foo'),
            os.path.join(top, 'mixed', f'{k:04d}_foo_a'),
            os.path.join(top, 'mixed', f'{k:04d}_foo_b'),
        ]:
            yield name


with concurrent.futures.ThreadPoolExecutor(max_workers=32) as executor:
    executor.map(lambda name: bucket.put_object(Key=name, Body='hi\n'.encode()), genkeys())

결과 구조는 다음과 같습니다.

./dirs/0000_dir/foo
./dirs/0001_dir/foo
./dirs/0002_dir/foo
...
./dirs/1999_dir/foo
./mixed/0000_dir/foo
./mixed/0000_foo_a
./mixed/0000_foo_b
./mixed/0001_dir/foo
./mixed/0001_foo_a
./mixed/0001_foo_b
./mixed/0002_dir/foo
./mixed/0002_foo_a
./mixed/0002_foo_b
...
./mixed/1999_dir/foo
./mixed/1999_foo_a
./mixed/1999_foo_b

위에 주어진 코드를 약간 조작하여s3listpaginator당신은 몇 가지 재미있는 사실들을 관찰할 수 있습니다.

  • Marker정말 배타적입니다. 해진정Marker=topdir + 'mixed/0500_foo_a'목록을 해당 키 다음으로 시작합니다(AmazonS3 API에 따라). 즉,.../mixed/0500_foo_b그것이 이유입니다.__prev_str().

  • 용사를 합니다.Delimiter을 할 때.mixed/의 각 .paginator에는 666개의 키와 334개의 공통 접두사가 있습니다.엄청난 반응을 일으키지 않는 것이 꽤 좋습니다.

  • 대적으로를 나열할 때, 나할때열.dirs/의 각 .paginator에는 1000개의 공통 접두사가 포함되어 있으며 키는 없습니다.

  • 의 형식으로 제한 통과PaginationConfig={'MaxItems': limit}키 수만 제한하고 공통 접두사는 제한하지 않습니다.우리는 반복기의 스트림을 더 잘라냄으로써 그것을 처리합니다.

이해하는 데 많은 시간이 걸렸지만 마지막으로 boto3를 사용하여 S3 버킷의 하위 폴더 내용을 나열하는 간단한 방법이 있습니다.도움이 되길 바랍니다.

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

같은 문제가 있었지만 사용하여 해결했습니다.boto3.client그리고.list_objects_v2와 함께Bucket그리고.StartAfter매개 변수

s3client = boto3.client('s3')
bucket = 'my-bucket-name'
startAfter = 'firstlevelFolder/secondLevelFolder'

theobjects = s3client.list_objects_v2(Bucket=bucket, StartAfter=startAfter )
for object in theobjects['Contents']:
    print object['Key']

위의 코드에 대한 출력 결과는 다음을 표시합니다.

firstlevelFolder/secondLevelFolder/item1
firstlevelFolder/secondLevelFolder/item2

Boto3 list_objects_v2 문서

다음에 대한 디렉터리 이름만 제거하려면secondLevelFolder나는 방금 파이썬 방법을 사용했습니다.split():

s3client = boto3.client('s3')
bucket = 'my-bucket-name'
startAfter = 'firstlevelFolder/secondLevelFolder'

theobjects = s3client.list_objects_v2(Bucket=bucket, StartAfter=startAfter )
for object in theobjects['Contents']:
    direcoryName = object['Key'].encode("string_escape").split('/')
    print direcoryName[1]

위의 코드에 대한 출력 결과는 다음을 표시합니다.

secondLevelFolder
secondLevelFolder

Python split() 문서

디렉터리 이름과 내용 항목 이름을 가져오려면 인쇄 줄을 다음으로 바꿉니다.

print "{}/{}".format(fileName[1], fileName[2])

다음과 같이 출력됩니다.

secondLevelFolder/item2
secondLevelFolder/item2

이것이 도움이 되길 바랍니다.

S3의 큰 이점은 폴더/디렉토리가 없고 키만 있다는 것입니다.겉보기 폴더 구조는 파일 이름 앞에 추가되어 '키'가 됩니다. 따라서 다음의 내용을 나열할 수 있습니다.myBucketsome/path/to/the/file/시도할 수 있습니다.

s3 = boto3.client('s3')
for obj in s3.list_objects_v2(Bucket="myBucket", Prefix="some/path/to/the/file/")['Contents']:
    print(obj['Key'])

그러면 다음과 같은 것을 얻을 수 있습니다.

some/path/to/the/file/yo.jpg
some/path/to/the/file/meAndYou.gif
...

다음은 저에게 도움이 됩니다.S3 객체:

s3://bucket/
    form1/
       section11/
          file111
          file112
       section12/
          file121
    form2/
       section21/
          file211
          file112
       section22/
          file221
          file222
          ...
      ...
   ...

사용:

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

다음을 확인:

form1/
form2/
...

포함:

resp = s3client.list_objects(Bucket=bucket, Prefix='form1/', Delimiter="/")
sections = [x['Prefix'] for x in resp['CommonPrefixes']] 

다음을 확인:

form1/section11/
form1/section12/

CLI를 때 AWS 하지 않고 이 합니다.aws s3 ls s3://my-bucket/그래서 저는 boto3를 사용하는 방법이 있을 것이라고 생각했습니다.

https://github.com/aws/aws-cli/blob/0fedc4c1b6a7aee13e2ed10c3ada778c702c22c3/awscli/customizations/s3/subcommands.py#L499

그들은 실제로 접두사와 구분 기호를 사용하는 것처럼 보입니다. 저는 그 코드를 조금 수정함으로써 버킷의 루트 수준에서 모든 디렉터리를 얻을 수 있는 함수를 작성할 수 있었습니다.

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

작업하는 것만큼 편리한 패키지를 사용하는 것은 어떻습니까?pathlib 꼭 를 사용해야 ,boto3:

용사를 합니다.boto3.resource

이는 itz-azhar의 답변을 기반으로 선택 사항을 적용합니다.limit그것은 분명히 사용하기가 훨씬 더 간단합니다.boto3.client판본

import logging
from typing import List, Optional

import boto3
from boto3_type_annotations.s3 import ObjectSummary  # pip install boto3_type_annotations

log = logging.getLogger(__name__)
_S3_RESOURCE = boto3.resource("s3")

def s3_list(bucket_name: str, prefix: str, *, limit: Optional[int] = None) -> List[ObjectSummary]:
    """Return a list of S3 object summaries."""
    # Ref: https://stackoverflow.com/a/57718002/
    return list(_S3_RESOURCE.Bucket(bucket_name).objects.limit(count=limit).filter(Prefix=prefix))


if __name__ == "__main__":
    s3_list("noaa-gefs-pds", "gefs.20190828/12/pgrb2a", limit=10_000)

용사를 합니다.boto3.client

이 기능은 다음과 같습니다.list_objects_v21000개 이상의 객체를 검색할 수 있도록 CpILL의 답변을 기반으로 합니다.

import logging
from typing import cast, List

import boto3

log = logging.getLogger(__name__)
_S3_CLIENT = boto3.client("s3")

def s3_list(bucket_name: str, prefix: str, *, limit: int = cast(int, float("inf"))) -> List[dict]:
    """Return a list of S3 object summaries."""
    # Ref: https://stackoverflow.com/a/57718002/
    contents: List[dict] = []
    continuation_token = None
    if limit <= 0:
        return contents
    while True:
        max_keys = min(1000, limit - len(contents))
        request_kwargs = {"Bucket": bucket_name, "Prefix": prefix, "MaxKeys": max_keys}
        if continuation_token:
            log.info(  # type: ignore
                "Listing %s objects in s3://%s/%s using continuation token ending with %s with %s objects listed thus far.",
                max_keys, bucket_name, prefix, continuation_token[-6:], len(contents))  # pylint: disable=unsubscriptable-object
            response = _S3_CLIENT.list_objects_v2(**request_kwargs, ContinuationToken=continuation_token)
        else:
            log.info("Listing %s objects in s3://%s/%s with %s objects listed thus far.", max_keys, bucket_name, prefix, len(contents))
            response = _S3_CLIENT.list_objects_v2(**request_kwargs)
        assert response["ResponseMetadata"]["HTTPStatusCode"] == 200
        contents.extend(response["Contents"])
        is_truncated = response["IsTruncated"]
        if (not is_truncated) or (len(contents) >= limit):
            break
        continuation_token = response["NextContinuationToken"]
    assert len(contents) <= limit
    log.info("Returning %s objects from s3://%s/%s.", len(contents), bucket_name, prefix)
    return contents


if __name__ == "__main__":
    s3_list("noaa-gefs-pds", "gefs.20190828/12/pgrb2a", limit=10_000)

버킷 아래의 첫 번째 수준 폴더만 검색하는 데는 이 작업이 잘 작동했습니다.

client = boto3.client('s3')
bucket = 'my-bucket-name'
folders = set()

for prefix in client.list_objects(Bucket=bucket, Delimiter='/')['CommonPrefixes']:
    folders.add(prefix['Prefix'][:-1])
    
print(folders)

폴더 이름이 고유하므로 집합이 아닌 목록에서도 동일한 작업을 수행할 수 있습니다.

이 질문에 대한 몇 가지 훌륭한 대답.

자원인 boto3를 해 왔습니다.objects.filter모든 파일을 가져오는 방법입니다.
objects.filter메소드는 반복기로 반환되며 매우 빠릅니다.
목록으로 변환하는 데 시간이 많이 걸립니다.

list_objects_v2반복자가 아닌 실제 내용을 반환합니다.
그러나 크기 제한이 1000이므로 모든 콘텐츠를 가져오려면 루프오버해야 합니다.

저는 폴더만 얻기 위해 이렇게 리스트 이해를 적용합니다.

[x.split('/')[index] for x in files]

다음은 다양한 방법에 소요되는 시간입니다.
이 테스트를 실행할 때 파일 수는 125077개였습니다.

%%timeit

s3 = boto3.resource('s3')
response = s3.Bucket('bucket').objects.filter(Prefix='foo/bar/')
3.95 ms ± 17.7 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
%%timeit

s3 = boto3.resource('s3')
response = s3.Bucket('foo').objects.filter(Prefix='foo/bar/')
files = list(response)
26.6 s ± 1.08 s per loop (mean ± std. dev. of 7 runs, 1 loop each)
%%timeit

s3 = boto3.client('s3')
response = s3.list_objects_v2(Bucket='bucket', Prefix='foo/bar/')
files = response['Contents']
while 'NextContinuationToken' in response:
    response = s3.list_objects_v2(Bucket='bucket', Prefix='foo/bar/', ContinuationToken=response['NextContinuationToken'])
    files.extend(response['Contents'])
22.8 s ± 1.11 s per loop (mean ± std. dev. of 7 runs, 1 loop each)

Boto 1.13.3의 경우, 그것은 그것처럼 간단합니다 (다른 답변에서 다루었던 페이지화 고려 사항을 모두 건너뛰면).

def get_sub_paths(bucket, prefix):
    s3 = boto3.client('s3')
    response = s3.list_objects_v2(
      Bucket=bucket,
      Prefix=prefix,
      MaxKeys=1000)
    return [item["Prefix"] for item in response['CommonPrefixes']]

이것은 제가 최근 프로젝트에서 사용한 것입니다.'paginator'를 사용하며 응답에 1000개 이상의 키가 반환되더라도 작동합니다.

import boto3

def list_folders(s3, bucket_name, prefix="", delimiter="/"):

    all = []
    paginator = s3.get_paginator("list_objects_v2")
    for page in paginator.paginate(Bucket=bucket_name, Prefix=prefix, Delimiter=delimiter):
        for common_prefix in page.get("CommonPrefixes", []):
            all.append(common_prefix)

    return [content.get('Prefix') for content in all]

s3_client = boto3.session.Session(profile_name="my_profile_name", region_name="my_region_name").client('s3')
folders = list_folders(s3_client, "my_bucket_name", prefix="path/to/folder")

가능한 해결책은 다음과 같습니다.

def download_list_s3_folder(my_bucket,my_folder):
    import boto3
    s3 = boto3.client('s3')
    response = s3.list_objects_v2(
        Bucket=my_bucket,
        Prefix=my_folder,
        MaxKeys=1000)
    return [item["Key"] for item in response['Contents']]

S3 버킷의 모든 고유 경로를 나열하는 재귀적 접근 방식 사용.

def common_prefix(bucket_name,paths,prefix=''):
    client = boto3.client('s3')
    paginator = client.get_paginator('list_objects')
    result = paginator.paginate(Bucket=bucket_name, Prefix=prefix, Delimiter='/')
    for prefix in result.search('CommonPrefixes'):
        if prefix == None:
            break
        paths.append(prefix.get('Prefix'))
        common_prefix(bucket_name,paths,prefix.get('Prefix'))

나열할 "dir"는 실제로 객체가 아니라 객체 키의 하위 문자열이므로 앞으로 표시되지 않습니다.objects.filter방법.당신은 고객의 것을 사용할 수 있습니다.list_objectsPrefix가 지정된 상태입니다.

import boto3

s3 = boto3.resource('s3')
bucket = s3.Bucket('my-bucket-name')
res = bucket.meta.client.list_objects(Bucket=bucket.name, Delimiter='/', Prefix = 'sub-folder/')
for o in res.get('CommonPrefixes'):
    print(o.get('Prefix'))

네, 이미 언급했듯이 중요한 것은 S3에 실제 폴더 개념이 없다는 것입니다.S3 API로 어떤 트릭이 가능한지 알아보겠습니다.

다음 예제는 @cem의 답변 솔루션을 개선한 것입니다.

@cem의 Soution 외에도 이 솔루션은 S3 paginator API를 사용합니다.솔루션은 결과에 1000개 이상의 개체가 포함된 경우에도 모든 결과를 수집합니다.S3 paginator API는 1001부터 2000까지 다음 결과를 자동으로 해결합니다.

이 예에서는 "랄라"라는 이름의 특정 "폴더" 아래에 있는 모든 "하위 폴더"(키)가 나열됩니다(해당 하위 폴더의 재귀적 구조는 없음).

접두사='랄라/' 및 구분 기호="/" 매개 변수가 마법을 부립니다.

# given "folder/key" structure
# .
# ├── lorem.txt
# ├─── lala
# │ ├── folder1
# │ │    ├── file1.txt
# │ │    └── file2.txt
# │ ├── folder2
# │ │    └── file1.txt
# │ └── folder3
# │      └── file1.txt
# └── lorem
#   └── folder4
#        ├── file1.txt
#        └── file2.txt

import boto3

s3 = boto3.client('s3')
paginator = s3.get_paginator('list_objects_v2')

# Execute paginated list_objects_v2
response = paginator.paginate(Bucket='your-bucket-name', Prefix='lala/', Delimiter="/")

# Get prefix for each page result
names = []
for page in response:
    names.extend([x['Prefix'] for x in page.get('CommonPrefixes', [])])

print(names)
# Result is:
# ['lala/folder1/','lala/folder2/','lala/folder3/']

우선 S3에는 실제 폴더 개념이 없습니다.당신은 확실히 파일을 가질 수 있습니다 @.'/folder/subfolder/myfile.txt'폴더도 하위 폴더도 없습니다.

S3에서 폴더를 "시뮬레이션"하려면 이름 끝에 '/'가 있는 빈 파일을 만들어야 합니다(Amazon S3 boto - 폴더 생성 방법 참조).

당신의 문제를 위해서, 당신은 아마도 그 방법을 사용해야 합니다.get_all_keys2개의 파라미터를 사용합니다.prefix그리고.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)

저는 boto3가 여기서 논의되는 주제라는 것을 알고 있지만, 저는 일반적으로 이러한 것에 단순히 awscli를 사용하는 것이 더 빠르고 직관적이라는 것을 알게 되었습니다. awscli는 가치보다 boto3보다 더 많은 기능을 보유하고 있습니다.

예를 들어, 지정된 버킷과 연결된 "하위 폴더"에 저장된 개체가 있는 경우 다음과 같은 모든 개체를 나열할 수 있습니다.

'mydata' = 버킷 이름

'f1/f2/f3' = "파일" 또는 개체로 이어지는 "경로"

'foo2.csv, 바파.segy, gar.tar' = 모든 객체 "점화" f3

따라서 이러한 개체로 이어지는 "절대 경로"는 'mydata/f1/f2/f3/foo2.csv'입니다.

awscli 명령을 사용하면 다음을 통해 주어진 "하위 폴더" 내의 모든 개체를 쉽게 나열할 수 있습니다.

aWS s3 ls s3://mydata/f1/f2/f3/ --message

많은 수의 S3 버킷 개체를 가져오려는 경우 페이지화를 처리할 수 있는 코드는 다음과 같습니다.

def get_matching_s3_objects(bucket, prefix="", suffix=""):

    s3 = boto3.client("s3")
    paginator = s3.get_paginator("list_objects_v2")

    kwargs = {'Bucket': bucket}

    # We can pass the prefix directly to the S3 API.  If the user has passed
    # a tuple or list of prefixes, we go through them one by one.
    if isinstance(prefix, str):
        prefixes = (prefix, )
    else:
        prefixes = prefix

    for key_prefix in prefixes:
        kwargs["Prefix"] = key_prefix

        for page in paginator.paginate(**kwargs):
            try:
                contents = page["Contents"]
            except KeyError:
                return

            for obj in contents:
                key = obj["Key"]
                if key.endswith(suffix):
                    yield obj

언급URL : https://stackoverflow.com/questions/35803027/retrieving-subfolders-names-in-s3-bucket-from-boto3