boto3からS3バケット内のサブフォルダー名を取得する


94

boto3を使用して、AWSS3バケットにアクセスできます。

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

現在、バケットにはフォルダが含まれています。フォルダfirst-level自体には、たとえばタイムスタンプで名前が付けられたいくつかのサブフォルダが含まれています1456753904534。私が行っている別の仕事のためにこれらのサブフォルダーの名前を知る必要があり、boto3にそれらを取得させることができるかどうか疑問に思います。

だから私は試しました:

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

これは辞書を提供し、そのキー 'Contents'は、第2レベルのタイムスタンプディレクトリではなく、すべての第3レベルのファイルを提供します。実際、次のようなものを含むリストを取得します。

{u'ETag ':' "etag" '、u'Key':first-level / 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ディレクトリの名前だけを取得したいのですが、この場合は特定のファイルが取得されていることがわかります。原則として、すべてのパスからディレクトリ名を取り除くことはできますが、3番目のレベルですべてを取得して2番目のレベルを取得するのは、醜くて費用がかかります。

私もここで報告され何かを試しました

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

しかし、私は希望するレベルのフォルダを取得していません。

これを解決する方法はありますか?


だからあなたはこれがうまくいかないと言っているのですか?それを実行するとどうなるか投稿していただけますか?
Jordon Phillips

1
@JordonPhillips送信したリンクの最初の行を試しましたが、ここに貼り付けました。テキストファイルはバケットの最初のレベルにあり、フォルダーはありません。
mar tin

@martinこの問題を解決したことはありますか。私は、すべてのバケットサブフォルダーの最初の要素が必要なという同様のジレンマに直面しています。
Ted Taylor of Life

1
@TedTaylorofLifeええ、すべてのオブジェクト/を取得し、分割してサブフォルダーを取得する以外の方法はありません
mar tin

1
@ mar tin私が行った唯一の方法は、出力を取得し、それをテキスト形式にスローし、「/」でコンマ区切りしてから、最初の要素をコピーして貼り付けることです。お尻の痛み。
Ted Taylor of Life

回答:


65

S3はオブジェクトストレージであり、実際のディレクトリ構造はありません。「/」はかなり見栄えがします。アプリケーションにツリーを維持/整理/追加できるため、ディレクトリ構造が必要になる理由の1つ。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 )

ドキュメンテーション

もう1つのオプションは、pythonos.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を使用すると、使用されるリソースの上にブラックボックスレイヤーが提供されます。


2
これにより、質問での試みと同じ結果が得られます。返されたオブジェクトからすべてのキーを取得し、文字列を分割してフォルダー名を取得することで、難しい方法を解決する必要があると思います。
mar tin

1
@martina:怠惰なPythonを分割し、リスト内の最後のデータを取得します。例:filename = keyname.split( "/")[-1]
mootmoot 2016年

1
@martindirectory_name = os.path.dirname(directory/path/and/filename.txt)およびfile_name = os.path.basename(directory/path/and/filename.txt)
jkdev 2016年

109

以下のコードは、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を参照してください。


12
特定のサブフォルダーのコンテンツを一覧表示したい場合はどうすればよいですか?
azhar22k 2017年

1
@ azhar22k、「サブフォルダ」ごとに関数を再帰的に実行できると思います。
SerbanCezar20年

1000を超える異なるプレフィックスがある場合はどうなりますか?
Kostrahb

42

短い答え

  • を使用しDelimiter='/'ます。これにより、バケットの再帰的なリストを作成する必要がなくなります。ここでのいくつかの回答は、完全なリストを作成し、文字列操作を使用してディレクトリ名を取得することを誤って示唆しています。これはひどく非効率的かもしれません。S3には、バケットに含めることができるオブジェクトの数に事実上制限がないことに注意してください。したがって、との間に1兆個のオブジェクトがあるbar/と想像してください。foo/取得するには、非常に長い時間がかかります['bar/', 'foo/']

  • を使用しPaginatorsます。同じ理由で(S3はエンジニアによる無限大の近似値です)、ページを介してリストし、すべてのリストをメモリに保存しないようにする必要あります。代わりに、「リスター」をイテレーターと見なし、それが生成するストリームを処理します。

  • boto3.clientではなく、を使用してくださいboto3.resourceresourceバージョンはうまく対処していないようDelimiterオプションを選択します。リソース、たとえば、bucket = boto3.resource('s3').Bucket(name)がある場合は、対応するクライアントを次のように取得できますbucket.meta.client

長い答え

以下は、単純なバケット(バージョン処理なし)に使用するイテレーターです。

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

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

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

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

        # non-recursive listing under some dir, listing only dirs:
        >>> for p in s3ls(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ディレクトリのみが含まれます(それぞれに1つのオブジェクトがあります)。mixeddirとオブジェクトの組み合わせが含まれ、各dirに2つのオブジェクトの比率があります(もちろん、dirの下に1つのオブジェクトがあります。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

s3listからの応答を検査するために上記のコードを少し修正すると、paginatorいくつかの楽しい事実を観察できます。

  • 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}制限を渡すと、共通のプレフィックスではなく、キーの数のみが制限されます。イテレータのストリームをさらに切り捨てることで、これに対処します。


@Mehdi:信じられないほどの規模と信頼性を提供するシステムとしては、それほど複雑ではありません。数百TBを超えるTBを扱ったことがあれば、それらが提供しているものに感謝するでしょう。ドライブのMTBFは常に0より大きいことを忘れないでください...大規模なデータストレージへの影響について考えてください。免責事項:私はアクティブで幸せなAWSユーザーであり、他の接続はありません。ただし、2007年からペタバイト規模のデータに取り組んでおり、以前ははるかに困難でした。
ピエール

39

理解するのにかなりの時間がかかりましたが、最後に、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))

3
フォルダに膨大な数のオブジェクトが含まれている場合はどうなりますか?
ピエールD

3
私のポイントは、これはひどく非効率的な解決策だということです。S3は、キー内の任意のセパレーターを処理するように構築されています。たとえば、'/'。これにより、オブジェクトでいっぱいの「フォルダ」を、ページネーションすることなくスキップできます。そして、完全なリスト(つまり、aws cliの「再帰的」に相当するもの)を主張する場合でも、ページネーターを使用する必要があります。そうしないと、最初の1000個のオブジェクトのみがリストされます。
ピエールD

これは素晴らしい答えです。それを必要とする人のために、私は私の導き出された答えでlimitそれに適用しました。
アキュメナス

16

S3の大きな認識は、キーだけのフォルダ/ディレクトリがないことです。見かけ上のフォルダ構造は、単にファイル名の前に付加されるので、内容を一覧表示するには、「キー」になるためにmyBucketS」some/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
...

これは良い答えですが、最大1000個のオブジェクトしか取得できず、それ以上は取得できません。より多くのオブジェクトを取得できる派生回答を作成しました。
アキュメナス

ええ、@ Acumenus私はあなたの答えがもっと複​​雑だと思います
CpILL

16

私は同じ問題があったが、それは使用して解決するために管理boto3.clientし、list_objects_v2Bucketして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

Boto3list_objects_v2ドキュメント

のディレクトリ名だけを取り除くために、secondLevelFolderPythonメソッドを使用しました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

お役に立てれば


9

以下は私のために働きます... 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/

バケットのルートに「フォルダ」が必要だったため、これが私にとって有効な唯一のソリューションです。プレフィックスは「」である必要がありますが、それ以外の場合は「/」で終わる必要があります
Oliver

7

AWS cliは、実行時にこれを実行します(おそらく、バケット内のすべてのキーをフェッチして反復することなく) 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

2

考えられる解決策は次のとおりです。

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

2

s3path作業と同じくらい便利なパッケージを使ってみません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_v2CpILLによる回答を使用および構築して、1000を超えるオブジェクトを取得できるようにします。

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)

0

まず第一に、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)

1
バケットオブジェクトにget_all_keysメソッドがないのではないかと思います。boto3バージョン1.2.3を使用しています。
mar tin

boto 1.2aをチェックしました。そこで、バケットにはとを使用したメソッドlistprefixありdelimiterます。私はそれがうまくいくはずだと思います。
Pirheas 2016年

1
質問に投稿したときに取得されたバケットオブジェクトには、これらのメソッドがありません。私はboto31.2.6を使用していますが、リンクはどのバージョンを参照していますか?
mar tin


0

boto3がここで説明されているトピックであることは知っていますが、通常、このような目的でawscliを使用する方が迅速で直感的です。awscliは、boto3よりも多くの機能を保持しています。

たとえば、特定のバケットに関連付けられた「サブフォルダ」に保存されたオブジェクトがある場合、次のようなものでそれらすべてを一覧表示できます。

1) 'mydata' =バケット名

2) 'f1 / f2 / f3' = "ファイル"またはオブジェクトにつながる "パス"

3) 'foo2.csv、barfar.segy、gar.tar' =「内部」のすべてのオブジェクトf3

したがって、これらのオブジェクトにつながる「絶対パス」は次のように考えることができます。'mydata/ f1 / f2 / f3 / foo2.csv '.. ..

awscliコマンドを使用すると、次の方法で特定の「サブフォルダー」内のすべてのオブジェクトを簡単に一覧表示できます。

aws s3 ls s3:// mydata / f1 / f2 / f3 / --recursive


0

以下は、多数の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

最初のページが「CommonPrefixes」でいっぱいで、「Contents」キーが提供されていない場合はどうなりますか。適切に実装すれば、不足しているコンテンツキーをスキップして、次のページに進むことができると思います。
JanVlcinsky20年

0

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']]
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.