AWS SDK for Python である Boto3 について、改めて ドキュメント を見ながら使い方を調べてみた。
動作環境
PyPIのページ によると、2系であれば2.6以上、3系では3.3以上で動作するとのこと。
以下は
- Python 3.4.3
- Boto3 1.1.3
の環境で動作確認している。
Boto3 の構成
What's New のページにある "Major Features" の項には、次の5つの機能について概要が記載されている。
- Resources : 高レベルなオブジェクト指向インターフェース
- Collections : 複数のリソースを操作するイテレータ
- Clients : 低レベルなサービス接続
- Paginators : 自動的なページング
- Waiters : 一定の状態に達するまで待機
自分はこの構成を理解できておらず、いままで Resources と Clients を混同してしまっていた。
なお、高レベルなAPIはすべての AWS サービスで使えるわけではなく、今のところ EC2 や S3 など一部のサービスでしか対応していないようだ。
インストールと事前準備
pip で簡単にインストールできる。
$ pip install boto3
AWS の操作には IAM のアクセスキーが必要なので、あらかじめマネージメントコンソールから作成して、ユーザーに適切なアクセス許可を設定しておく。
端末側ではアクセスキーの情報を ~/.aws/credentials
に設定する。
awscli を使っているのであれば aws configure
をした際にすでにこのファイルが生成されているが、そうでない場合は awscli のセットアップをするか、 credentials ファイルに直接アクセスキーを設定する。
[default]
aws_access_key_id = YOUR_ACCESS_KEY
aws_secret_access_key = YOUR_SECRET_KEY
高レベルAPIでS3バケットへアクセスする
S3.Bucket オブジェクトを通して、バケットへアクセスすることができる。
import boto3
# バケット名
AWS_S3_BUCKET_NAME = 'hogehoge'
s3 = boto3.resource('s3')
bucket = s3.Bucket(AWS_S3_BUCKET_NAME)
print(bucket.name)
# => hogehoge
属性 objects
を通して、バケットに保存されているS3オブジェクトの情報にアクセスできる。
この属性は Bucket.objectsCollectionManager
クラスのインスタンスで、 all()
, delete()
, filter()
, limit()
, page_size()
のメソッドが利用できる。これらのメソッドは s3.Bucket.objectsCollection
クラスのインスタンスを返し、このオブジェクトをイテレートすることで ObjectSummary
クラスのインスタンスを得ることができる。
print(bucket.objects.all())
# => s3.Bucket.objectsCollection(s3.Bucket(name='hogehoge'), s3.ObjectSummary)
print([obj_summary.key for obj_summary in bucket.objects.all()])
# => ['hayabusa.txt']
objects
を使った操作は、バケットに保存されているオブジェクトを探す場合など対象のオブジェクトが特定されていない場合に有効である。
高レベルAPIでS3バケットからオブジェクトを取得する
キーがわかっているS3オブジェクトを取得する場合は、 S3.Object クラスを使う。
GET_OBJECT_KEY_NAME = 'hayabusa.txt'
obj = bucket.Object(GET_OBJECT_KEY_NAME)
print(obj.key)
# => hayabusa.txt
Object
オブジェクトは Bucket オブジェクトを介さずにバケット名とキー名を指定することで生成することもできる。
obj = s3.Object(AWS_S3_BUCKET_NAME, GET_OBJECT_KEY_NAME)
print(obj.key)
# => hayabusa.txt
S3オブジェクトの中身を取得するには、オブジェクトの get()
メソッドを使用する。
get()
メソッドの戻り値は辞書で、その辞書の中にある Body
を通してオブジェクトの中身を参照することができる。
この Body
は botocore.response.StreamingBody
クラスのインスタンスで、バイト型データを扱うストリームとなっている。そのため、文字列として扱うためにはストリームから読み込んで文字列型に変換する必要がある。
response = obj.get()
body = response['Body'].read()
print(type(body))
# => <class 'bytes'>
print(body.decode('utf-8'))
# => 東京〜新函館北斗 10往復
# 仙台〜新函館北斗 1往復
なお、ストリームはいったん read()
してしまうとストリームの末尾にシークされてしまうため、2回目以降の呼び出しでは結果を取得できないので注意が必要である。
高レベルAPIでS3バケットにオブジェクトを追加する
取得と同様、 Object
オブジェクトを使うことで、新規にバケットへS3オブジェクトを追加したり、中身を更新したりすることができる。
S3オブジェクトの中身を設定するには、 put()
メソッドの引数 Body
に保存したい内容をバイト列として渡せばよい。 ACL
や ContentType
など、細かなオプションを引数で指定することもできる。
PUT_OBJECT_KEY_NAME = 'hayate.txt'
obj = bucket.Object(PUT_OBJECT_KEY_NAME)
body = """盛岡〜新函館北斗 1往復
新青森〜新函館北斗 1往復
"""
response = obj.put(
Body=body.encode('utf-8'),
ContentEncoding='utf-8',
ContentType='text/plane'
)
低レベルAPIを使った操作
S3.Client オブジェクトを使うことで、低レベルなAPIを使用した操作も可能である。
例えば、S3オブジェクトの取得は低レベルAPIを使って次のように書くこともできる。
s3 = boto3.resource('s3')
client = s3.meta.client
response = client.get_object(Bucket=AWS_S3_BUCKET_NAME, Key=GET_OBJECT_KEY_NAME)
body = response['Body'].read()
print(body.decode('utf-8'))
# => 東京〜新函館北斗 10往復
# 仙台〜新函館北斗 1往復
まとめ
いままでは低レベルなAPI( Clients )と高レベルなAPI( Resources )を混同して使用していた。
低レベルAPIでしか提供されていない機能も一部あるが、オブジェクト指向なプログラムを書くことができるので高レベルなAPIがあるのであればそちらを使用した方がいいだろう。