はじめに

Python boto3 を使って、AWS S3 にファイルのアップロードや削除方法を調べた。

TL;DR

  • アップロードは boto3.resource("s3").Bucket("your-bucket").upload_file
    • 公開状態にしたい場合は、Bucket そのもののブロックパブリックアクセスをオフにして、ExtraArgs={"ACL": "public-read"} を付ける
    • 画像をブラウザで開きたい場合は、ExtraArgs={"ContentType": "image/jpeg"} などを付ける
  • 削除は boto3.resource("s3").Bucket("your-bucket").delete_objects

目的・やったこと

Python boto3 を使って、AWS S3 にファイルのアップロードや削除方法を調べた。

目次

  1. はじめに
  2. TL;DR
  3. 目的・やったこと
  4. 環境・条件
  5. 詳細
    1. boto3 インストール
    2. 認証情報の登録
    3. S3 へのアクセス確認
    4. ファイルアップロード
      1. 公開状態でアップロード
      2. 画像をアップロード(ブラウザで開ける状態にする)
    5. bucket の中身を消す
      1. bucket の中身をまとめて消す
  6. まとめ
  7. その他・メモ
  8. 参考文献

環境・条件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
$ sw_vers
ProductName: Mac OS X
ProductVersion: 10.14.5
BuildVersion: 18F132

$ pyenv --version
pyenv 1.2.13

$ python --version
Python 3.6.2 :: Anaconda, Inc.

$ pip --version
pip 19.1.1 from /Users/r17n/.pyenv/versions/anaconda3-5.0.0/lib/python3.6/site-packages/pip (python 3.6)

$ pip show boto3
Name: boto3
Version: 1.9.200

詳細

boto3 インストール

pipboto3 をインストール。

1
$ pip install boto3

認証情報の登録

事前に 【AWS】【S3】作成手順 & アップロード手順 & アクセス権限設定手順 などで Bucket やユーザーは作っておくこと。

Botoを使用してPythonからAWSを操作する(入門編) - Qiita では、~/.aws/credentials にアクセスキーなどの情報を記載するとあるが、個人的には環境ごとに隔離したい。

公式ドキュメント - Configuring Credentials によると、以下の順番で認証情報を探すとのこと。

  1. Passing credentials as parameters in the boto.client() method
  2. Passing credentials as parameters when creating a Session object
  3. Environment variables
  4. Shared credential file (~/.aws/credentials)
  5. AWS config file (~/.aws/config)
  6. Assume Role provider
  7. Boto2 config file (/etc/boto.cfg and ~/.boto)
  8. Instance metadata service on an Amazon EC2 instance that has an IAM role configured.

ざっくり上からこんな感じ、6〜8 はほぼ気にしなくて良さそうなので省略。

  1. boto.client() の引数
  2. boto3.session() の引数
  3. 環境変数
  4. ~/.aws/credentials
  5. ~/.aws/config

今回は direnv で環境変数をセットすることにした。以下の3つを設定しておけば OK。

  • AWS_ACCESS_KEY_ID
  • AWS_SECRET_ACCESS_KEY
  • AWS_DEFAULT_REGION
1
2
3
4
$ direnv edit .
export AWS_ACCESS_KEY_ID=YourAccessKeyId
export AWS_SECRET_ACCESS_KEY=YourSecretAccessKey
export AWS_DEFAULT_REGION=ap-northeast-1

他の利用可能な環境変数は 公式ドキュメント - Environment Variable Configuration を参照。

S3 へのアクセス確認

以下のコードを実行して、(Policy に応じて取得可能な) bucket の一覧が表示されれば無事にアクセスできている。

1
2
3
4
import boto3
s3 = boto3.resource("s3")
print(list(s3.buckets.all()))
# => [s3.Bucket(name='your-bucket')]

ファイルアップロード

upload_file メソッドでアップロード。

1
2
bucket = s3.Bucket("your-bucket")
bucket.upload_file("path/to/file", "path/of/s3/file")

公開状態でアップロード

ExtraArgs={"ACL": "public-read"} オプションを付けてアップロードすると、対象ファイルが公開状態になる。

1
bucket.upload_file("path/to/file", "path/of/s3/file", ExtraArgs={"ACL": "public-read"})

なお、bucket のブロックパブリックアクセス設定がオンの場合、上記コードは例外が発生するので注意。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
Traceback (most recent call last):
File "/Users/r17n/.pyenv/versions/anaconda3-5.0.0/lib/python3.6/site-packages/boto3/s3/transfer.py", line 279, in upload_file
future.result()
File "/Users/r17n/.pyenv/versions/anaconda3-5.0.0/lib/python3.6/site-packages/s3transfer/futures.py", line 106, in result
return self._coordinator.result()
File "/Users/r17n/.pyenv/versions/anaconda3-5.0.0/lib/python3.6/site-packages/s3transfer/futures.py", line 265, in result
raise self._exception
File "/Users/r17n/.pyenv/versions/anaconda3-5.0.0/lib/python3.6/site-packages/s3transfer/tasks.py", line 126, in __call__
return self._execute_main(kwargs)
File "/Users/r17n/.pyenv/versions/anaconda3-5.0.0/lib/python3.6/site-packages/s3transfer/tasks.py", line 150, in _execute_main
return_value = self._main(**kwargs)
File "/Users/r17n/.pyenv/versions/anaconda3-5.0.0/lib/python3.6/site-packages/s3transfer/upload.py", line 692, in _main
client.put_object(Bucket=bucket, Key=key, Body=body, **extra_args)
File "/Users/r17n/.pyenv/versions/anaconda3-5.0.0/lib/python3.6/site-packages/botocore/client.py", line 357, in _api_call
return self._make_api_call(operation_name, kwargs)
File "/Users/r17n/.pyenv/versions/anaconda3-5.0.0/lib/python3.6/site-packages/botocore/client.py", line 661, in _make_api_call
raise error_class(parsed_response, operation_name)
botocore.exceptions.ClientError: An error occurred (AccessDenied) when calling the PutObject operation: Access Denied

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/Users/r17n/.pyenv/versions/anaconda3-5.0.0/lib/python3.6/site-packages/boto3/s3/inject.py", line 209, in bucket_upload_file
ExtraArgs=ExtraArgs, Callback=Callback, Config=Config)
File "/Users/r17n/.pyenv/versions/anaconda3-5.0.0/lib/python3.6/site-packages/boto3/s3/inject.py", line 131, in upload_file
extra_args=ExtraArgs, callback=Callback)
File "/Users/r17n/.pyenv/versions/anaconda3-5.0.0/lib/python3.6/site-packages/boto3/s3/transfer.py", line 287, in upload_file
filename, '/'.join([bucket, key]), e))

画像をアップロード(ブラウザで開ける状態にする)

何も考えずにそのまま画像をアップロードすると、ブラウザアクセス時にダウンロードが始まってしまう。ブラウザで画像を表示したい場合には、ExtraArgs={"ContentType": "image/jpeg"} などのように Content-Type を指定する。

1
bucket.upload_file("hoge.jpg", "hoge.jpg", ExtraArgs={"ContentType": "image/jpeg", "ACL": "public-read"})

bucket の中身を消す

アップロード時に指定した Keydelete_objects に渡せば OK。

1
2
3
4
5
6
7
8
bucket.delete_objects(
Delete={
"Objects": [
{"Key": "hoge.jpg"},
{"Key": "fuga.jpg"}
]
}
)

bucket の中身をまとめて消す

objects.all() で、bucket 内の Object が取れるので、delete_objectsKey を渡せば OK。

1
2
3
4
5
6
7
8
for o in bucket.objects.all():
bucket.delete_objects(
Delete={
"Objects": [
{"Key": o.key}
]
}
)

まとめ

  • アップロードは boto3.resource("s3").Bucket("your-bucket").upload_file
    • 公開状態にしたい場合は、Bucket そのもののブロックパブリックアクセスをオフにして、ExtraArgs={"ACL": "public-read"} を付ける
    • 画像をブラウザで開きたい場合は、ExtraArgs={"ContentType": "image/jpeg"} などを付ける
  • 削除は boto3.resource("s3").Bucket("your-bucket").delete_objects

その他・メモ

Available Services を見ると、やれることが大量にあるので、API 使った自動化が捗りそう。

参考文献

関連記事