やりたいこと
- list_objectsで指定S3バケット上のキー一覧を取得
- あるキーが存在するならファイルにデータを追記
- あるキーが存在しない場合ファイルを新規作成
- ランタイムはPython3.9
①LambdaからS3バケットにアクセスできない
Error
[ERROR] ClientError: An error occurred (AccessDenied) when calling the ListObjects operation: Access Denied
Traceback (most recent call last):
解決策:LambdaにS3のアクセス権限を付与
1.Lambda関数を管理しているIAMロールの概要ページにアクセス
2.「許可を追加」→「ポリシーをアタッチ」を選択
3.追加したいポリシーを選んで「ポリシーをアタッチ」
※私はこのあと書き込み等も行いたかったため「AmazonS3FullAccess」を追加しましたが、読み込みだけなら「AmazonS3ReadOnlyAccess」で問題ありません。
②キー名のみの取得ができない
失敗例
Example1
import boto3
s3_client = boto3.client("s3")
bucket = "testbucket" #バケット名
response = s3_client.list_objects(Bucket=bucket)
print("##keylist")
print(response)
Result1
##keylist
{'ResponseMetadata': {'RequestId': '##########', 'HostId': '##########', 'HTTPStatusCode': 200, 'HTTPHeaders': {'x-amz-id-2': '##########', 'x-amz-request-id': '##########', 'date': 'Fri, 12 Aug 2022 07:46:36 GMT', 'x-amz-bucket-region': 'ap-northeast-1', 'content-type': 'application/xml', 'transfer-encoding': 'chunked', 'server': 'AmazonS3'}, 'RetryAttempts': 0}, 'IsTruncated': False, 'Marker': '', 'Contents': [{'Key': 'apple.txt', 'LastModified': datetime.datetime(2022, 8, 12, 5, 19, 14, tzinfo=tzlocal()), 'ETag': '"##########"', 'Size': 0, 'StorageClass': 'STANDARD', 'Owner': {'DisplayName': '##########', 'ID': '##########'}}, {'Key': 'grape.txt', 'LastModified': datetime.datetime(2022, 8, 12, 5, 19, 14, tzinfo=tzlocal()), 'ETag': '"##########"', 'Size': 0, 'StorageClass': 'STANDARD', 'Owner': {'DisplayName': '##########', 'ID': '##########'}}, {'Key': 'peach.txt', 'LastModified': datetime.datetime(2022, 8, 12, 5, 19, 14, tzinfo=tzlocal()), 'ETag': '"##########"', 'Size': 0, 'StorageClass': 'STANDARD', 'Owner': {'DisplayName': '##########', 'ID': '##########'}}], 'Name': 'testbucket', 'Prefix': '', 'MaxKeys': 1000, 'EncodingType': 'url'}
キー名のみがリストで返されるものだと勘違いしていました。(一部伏字にしています)
解決策
Example2
import boto3
s3_client = boto3.client("s3")
bucket = "testbucket" #バケット名
response = s3_client.list_objects(Bucket=bucket)
keys = []
for r in response.get("Contents")
keys.append(r.get("Key"))
print("##keylist")
print(keys)
Result2
##keylist
['apple.txt', 'grape.txt', 'peach.txt']
おまけ
指定S3バケットにあるキーが存在するかどうかで処理を分岐させる例文
Example3
import boto3
def lambda_handler(event, context):
bucket = BUCKET #バケット名
key = KEY #探したいキー名
s3_client = boto3.client("s3")
response = s3_client.list_objects(Bucket=bucket)
keys = []
for r in response.get("Contents")
keys.append(r.get("Key"))
if key in keys:
#キーが存在する場合の処理
else:
#キーが存在しない場合の処理
return {"statuscode":200}
参考