Boto3を使ってS3バケットのオブジェクトバージョンをページネーションで取得する方法
はじめに
バージョニングが有効化されたS3バケットには、同一オブジェクトの複数バージョンが保存されるため、オブジェクト数が多いほど一度のAPI呼び出しですべてを取得するのは困難になります。本記事では、Pythonのboto3ライブラリを使用して、AWSアカウント内のS3バケット(AWS Glue Data Catalogのデータソースとしても利用されるバケットを含む)に保存されたオブジェクトバージョンを、ページネーション(ページ分割)しながら効率的に取得する方法を解説します。
課題
boto3ライブラリをPythonで使用し、自分のアカウントに作成されたS3バケットのオブジェクトバージョンをページ分割して取得することを目標とします。
解決のためのアプローチとアルゴリズム
ステップ1: boto3およびbotocoreの例外クラスをインポートし、例外処理に備えます。
ステップ2: 関数のパラメータを把握します。bucket_nameは必須パラメータ、max_items・page_size・starting_tokenは任意パラメータです。
max_items: 返却するレコードの総数を指定します。利用可能なレコード数がmax_itemsを超える場合、レスポンスにNextTokenが含まれ、それを使ってページネーションを再開できます。
page_size: 1ページあたりのレコード数を指定します。
starting_token: ページネーションの開始位置を指定します。前回のレスポンスから得られたNextKeyMarkerなどを渡します。
ステップ3: boto3ライブラリでAWSセッションを作成します。デフォルトプロファイルにregion_nameが設定されていることを確認してください。設定されていない場合は、セッション作成時に明示的にregion_nameを渡します。
ステップ4: S3用のAWSクライアントを作成します。
ステップ5: list_object_versions操作をもとに、S3バケットのオブジェクトバージョン情報を扱うpaginatorオブジェクトを作成します。
ステップ6: paginate関数を呼び出し、max_items・page_size・starting_tokenをPaginationConfigパラメータとして、bucket_nameをBucketパラメータとして渡します。
ステップ7: max_itemsとpage_sizeの設定に応じた件数のレコードが返されます。
ステップ8: ページネーション中にエラーが発生した場合は、ClientErrorなどの例外を適切に処理します。
サンプルコード
以下のコードを使用すると、ユーザーアカウントに作成されたS3バケットのオブジェクトバージョンをページ分割して取得できます。
import boto3
from botocore.exceptions import ClientError
def paginate_through_object_version_s3_bucket(bucket_name, max_items=None, page_size=None, starting_token=None):
session = boto3.session.Session()
s3_client = session.client('s3')
try:
paginator = s3_client.get_paginator('list_object_versions')
response = paginator.paginate(
Bucket=bucket_name,
PaginationConfig={
'MaxItems': max_items,
'PageSize': page_size,
'StartingToken': starting_token
}
)
return response
except ClientError as e:
raise Exception('boto3 client error in paginate_through_object_version_s3_bucket: ' + str(e))
except Exception as e:
raise Exception('Unexpected error in paginate_through_object_version_s3_bucket: ' + str(e))
# 1回目の実行:最初のページを取得
a = paginate_through_object_version_s3_bucket('s3-test-bucket', 2, 5)
print(*a)
# 2回目の実行:NextKeyMarkerを使って続きを取得
for items in a:
next_token = items['NextKeyMarker']
b = paginate_through_object_version_s3_bucket('s3-test-bucket', 2, 5, next_token)
print(*b)
実行結果
上記のコードを実行すると、まず最初のページが取得されます。レスポンス内のIsTruncatedがTrueの場合、まだ未取得のバージョンが残っていることを意味し、NextKeyMarkerの値を次回のstarting_tokenとして渡すことで、続きのページを取得できます。
1回目の実行結果
{'ResponseMetadata': {'RequestId': 'XEVY**************CD0', 'HTTPStatusCode': 200, 'RetryAttempts': 0},
'IsTruncated': True, 'KeyMarker': '', 'VersionIdMarker': '',
'NextKeyMarker': 'analytics-s3/template.json', 'NextVersionIdMarker': 'null',
'Versions': [
{'ETag': '"e66659e02"', 'Size': 1554, 'StorageClass': 'STANDARD',
'Key': 'analytics-s3i/param.json', 'VersionId': 'null', 'IsLatest': True,
'LastModified': datetime.datetime(2020, 10, 29, 19, 50, 55, tzinfo=tzutc()),
'Owner': {'DisplayName': 'AWS.Development', 'ID': '928b5bd**************3d70'}},
{'ETag': '"22a4bf7**************9c1ed2612"', 'Size': 1756, 'StorageClass': 'STANDARD',
'Key': 'analytics-s3i/params.json', 'VersionId': 'null', 'IsLatest': True,
'LastModified': datetime.datetime(2021, 3, 10, 20, 10, 47, tzinfo=tzutc()),
'Owner': {'DisplayName': 'AWS.Development', 'ID': '928b5bde*****************2d4423d70'}}],
'Name': 's3-test-bucket', 'Prefix': '', 'MaxKeys': 5, 'EncodingType': 'url',
'DeleteMarkers': None, 'CommonPrefixes': None}
2回目の実行結果(NextKeyMarkerを渡して継続取得)
{'ResponseMetadata': {'RequestId': '3V9*********703V', 'HTTPStatusCode': 200, 'RetryAttempts': 0},
'IsTruncated': True, 'KeyMarker': 'analytics-s3i2/template.json', 'VersionIdMarker': '',
'NextKeyMarker': 'analytics-s3l/params.json', 'NextVersionIdMarker': 'null',
'Versions': [
{'ETag': '"dbd336ff00cb5af3d"', 'Size': 1557, 'StorageClass': 'STANDARD',
'Key': 'analytics-s3i3/param.json', 'VersionId': 'null', 'IsLatest': True,
'LastModified': datetime.datetime(2020, 10, 28, 18, 16, 38, tzinfo=tzutc()),
'Owner': {'DisplayName': 'AWS.Development', 'ID': '*****************'}},
{'ETag': '"66b49598df6"', 'Size': 21334, 'StorageClass': 'STANDARD',
'Key': 'analytics-s3i3/template.json', 'VersionId': 'null', 'IsLatest': True,
'LastModified': datetime.datetime(2020, 10, 28, 18, 16, 38, tzinfo=tzutc()),
'Owner': {'DisplayName': 'AWS.Development', 'ID': '****************'}}],
'Name': 's3-test-bucket', 'Prefix': '', 'MaxKeys': 5, 'EncodingType': 'url',
'DeleteMarkers': None, 'CommonPrefixes': None}
ポイントのまとめ
get_paginator('list_object_versions') を使うことで、S3のバージョン情報を自動的にページ分割して取得できます。
PaginationConfig の MaxItems/PageSize/StartingToken を組み合わせることで、取得件数と1ページあたりのサイズを柔軟に制御できます。
レスポンスの IsTruncated がTrueの間は NextKeyMarker を次の開始トークンとして渡し、全バージョンをループで取得します。
大量のオブジェクトを持つバケットを扱う場合でも、この方法ならメモリ負荷を抑えながら安定してデータを取得できます。
-
Boto3を使ってAWS Glueのセキュリティ設定から指定したセキュリティ構成の詳細を取得する方法
課題Pythonのboto3ライブラリを使用して、AWS Glueセキュリティに存在する指定されたセキュリティ構成(Security Configuration)の詳細情報を取得します。例 − AWS Glueセキュリティに存在する「job-security-settings」というセキュリティ構成の詳細を取得します。解決のためのアプローチとアルゴリズムステップ1 − boto3とbotocoreの例外処理用モジュールをインポートし、例外を適切にハンドリングできるようにします。ステップ2 − security_nameは必須パラメータです。ここには、詳細を取得したいセキュリティ構成の名前を指定
-
Boto3を使ってAWS Glueのジョブを削除する方法を徹底解説
AWS Glueは、ETL(抽出・変換・ロード)処理を簡単に実行できるサーバーレスのデータ統合サービスです。本記事では、Pythonのboto3ライブラリを使用して、自分のAWSアカウント内に作成済みのGlueジョブを削除する方法を、ステップごとにわかりやすく解説します。 課題 Pythonのboto3ライブラリを使って、AWSアカウント内に作成されたGlueジョブを削除します。 例: アカウント内に作成された「transfer_from_s3」というGlueジョブを削除します。 解決のためのアプローチとアルゴリズム ステップ1: 例外処理のために、boto3とbotocoreの例外モジュール