S3のバケット内のオブジェクトをすべて取得する
サンプルコード
Boto3には高レベルAPIと低レベルAPIがあります。 高レベルAPIはクラスベースで実装されており、より少ないコード量で記述が可能です。 低レベルAPIではより細かい制御が可能です。 基本的には高レベルAPIの仕様をおすすめします。
高レベルAPI
import boto3 s3 = boto3.resource('s3') def get_all_objects_high(bucket): bucket = s3.Bucket(bucket) return bucket.objects.all() objs = get_all_objects_high(TARGET_BUCKET) for i,obj in enumerate(iter(objs)): logger.info(f'{i}: {obj.key}') => 0: xxx 1: yyy 2: zzz
bucket.objects
の返り値はObjectSummary
のCollection
です。
今回はall()
メソッドを使用してすべてのオブジェクトを取得しています。
ObjectSummaryの仕様は以下の通りです。
↑のサンプルコードではkey
を使用しています。
Collectionは以下のようなものです。 プレフィックスによるフィルタリングやページネーションがメソッドのチェーンで行えるので便利です。
オブジェクトのBodyは含まれていないので、ObjectSummary
のget
を使用して取得する必要があります。
低レベルAPI
import boto3 s3 = boto3.client('s3') def get_all_objects_low(bucket): continuation_token = None while True: if continuation_token is None: res = s3.list_objects_v2( Bucket=bucket, MaxKeys=2 ) else: res = s3.list_objects_v2( Bucket=bucket, ContinuationToken=continuation_token ) # バケットが空の場合Contentsフィールドがなくなる if res['KeyCount'] == 0: break for content in res['Contents']: yield content # ContinuationTokenが渡されなかったらそこで終わり continuation_token = res.get('NextContinuationToken') if continuation_token is None: break objs = get_all_objects_low(TARGET_BUCKET) for i,obj in enumerate(iter(objs)): logger.info(f'{i}: {obj["Key"]}') => 0: xxx 1: yyy 2: zzz
コードとしては上記のget_all_objects
がそれに該当します。
バケット名を引数に渡すことで、そのバケット内のオブジェクトの情報(ボディ含まない)を取得可能です。
今回はS3のlist_objcets_v2
を使用しています。
関数自体はジェネレータになっているので、1000個単位でS3にリクエストを送り、情報を取得しています。 関数の返り値としては以下のようなものが返されます。 入っている内容はObjectSummaryと同じです。
{ 'Key': 'string', 'LastModified': datetime(2015, 1, 1), 'ETag': 'string', 'ChecksumAlgorithm': [ 'CRC32'|'CRC32C'|'SHA1'|'SHA256', ], 'Size': 123, 'StorageClass': 'STANDARD'|'REDUCED_REDUNDANCY'|'GLACIER'|'STANDARD_IA'|'ONEZONE_IA'|'INTELLIGENT_TIERING'|'DEEP_ARCHIVE'|'OUTPOSTS'|'GLACIER_IR', 'Owner': { 'DisplayName': 'string', 'ID': 'string' } }
BodyやContentTypeなどは含まれていないので必要な場合は別途、get_object
などの関数で取得する必要があります。
最後に
今回は2つのサンプルコードを書いてみました。 改めて見ると、低レベルAPIはコード量が多いです。(高レベルAPIに感謝) ただ、やっぱり細かい制御を行いたい場合もあるので両方あると便利ですね。