PythonでAWS S3/Azure BlobStorage/GCP CloudStorageにファイルをアップロード/ダウンロードしてみた

この記事は[Pathee Advent Calendar 2019](https://qiita.com/advent-calendar/2019/pathee)の10日目の記事です。

## はじめに
こんにちは。エンジニアの國井です。

**Python**で**AWS S3**/**Azure BlobStorage**/**GCP CloudStorage**にファイルをアップロード/ダウンロードする方法をまとめてみました。

以前、PythonでAzure BlobStorageにファイルをアップロード/ダウンロードしたことがあり、その流れで他のストレージサービスでもいっちょやってみようと思ったのがキッカケです。

AWS S3/GCP Cloud Storageを選んだのは何となくで、
Pythonなのは、弊社のバックエンドがPythonで実装されているから、といったところです。

各ストレージサービスに対して、以下の項目でまとめていきます。

・**事前準備**
　・ **接続情報の設定**
　・ **モジュールのインストール**
・**ファイルを格納する箱を作成する**
・**作成した箱にファイルをアップロードする**
・**作成した箱からファイルをダウンロードする**
・**作成した箱を削除する**

どのストレージサービスでもモジュールが用意されているので、そのモジュールを使えばわりと簡単にできます。

## 環境
Python 3.6.4
macOS 10.15.1

## AWS S3
### 事前準備
#### 接続情報の設定
接続情報として、**アクセスキーID**と**シークレットアクセスキー**が必要になります。
[AWSアクセスキー作成](https://qiita.com/miwato/items/291c7a8c557908de5833) を参考に、アクセスキーIDとシークレットアクセスキーを作成します。

以下のコマンドで、環境変数にアクセスキーIDとシークレットアクセスキーを設定します。

```sh
$ export AWS_ACCESS_KEY_ID="アクセスキーID"
$ export AWS_SECRET_ACCESS_KEY="シークレットアクセスキー"
```

#### モジュールのインストール
**boto3**をインストールします。

```sh
$ pip install boto3
```

以降のAWS S3に対する各操作をする上で、以下のコードで作成した**s3_resource**がベースになります。

```py
import  boto3

s3_resource = boto3.resource('s3', region_name='ap-northeast-1')
```


### バケットの作成
AWS S3において、ファイルを格納する箱は**バケット**と呼ばれます。
以下のコードで、バケットを作成できます。

```py
# バケットの作成
s3_client = s3_resource.meta.client
s3_client.create_bucket(Bucket='作成するバケットの名前', CreateBucketConfiguration={'LocationConstraint': 'ap-northeast-1'})
```
CreateBucketConfigurationにはいろいろ設定項目がありそうですが、とりあえずLocationConstraint（バケット作成先のリージョンの制約）だけでも作成できます。

### ファイルのアップロード
```py
# ファイルのアップロード
s3_resource.Bucket('アップロード先のバケットの名前').upload_file('アップロードするファイルのパス', 'アップロード先でのファイル名')
```

### ファイルのダウンロード
```py
# ファイルのダウンロード
s3_resource.Bucket('ダウンロード元のバケットの名前').download_file('ダウンロードするファイル名', 'ダウンロード先のファイルのパス')
```

### バケットの削除
```py
# バケットの削除
s3_client = s3_resource.meta.client
s3_client.delete_bucket(Bucket='削除するバケットの名前')
```
バケットを削除するためには、バケットにアップロードしたファイルを全て削除して空っぽにしておく必要あります。
バケットが空っぽでない状態でバケットを削除しようとするとエラーになって削除できません。

以下のコードで、アップロードしたファイルを削除できますが、ファイル名を指定して削除する方法しかわからず、、、（delete_objectsメソッドもありますが、こちらも結局ファイル名を指定しないといけなさそう）

```py
# ファイルの削除
s3_client = s3_resource.meta.client
s3_client.delete_object(Bucket='削除するファイルを含むバケットの名前', Key='削除するファイル名')
```


## Azure BlobStorage
### 事前準備
#### 接続情報の設定
接続情報として、ストレージアカウントの**接続文字列**が必要になります。

AzurePortalにサインインして、[ストレージアカウントを作成](https://docs.microsoft.com/ja-jp/azure/storage/common/storage-quickstart-create-account?tabs=azure-portal) します。
[こちら](https://docs.microsoft.com/ja-jp/azure/storage/blobs/storage-quickstart-blobs-python#copy-your-credentials-from-the-azure-portal) を参考に、ストレージアカウントの接続文字列を取得（コピー）します。

以下のコマンドで、環境変数に接続文字列を設定します。

```sh
$ export CONNECT_STR="接続文字列"
```

#### モジュールのインストール
**azure-storage-blob**をインストールします。

```sh
$ pip install azure-storage-blob
```

以降のAzure BlobStorageに対する各操作をする上で、以下のコードで作成した**blob_service_client**がベースになります。

```py
import os
from azure.storage.blob import BlobServiceClient

connect_str = os.getenv('CONNECT_STR')
blob_service_client = BlobServiceClient.from_connection_string(connect_str)
```

### コンテナの作成
Azure BlobStorageにおいて、ファイルを格納する箱は**コンテナ**と呼ばれます。
以下のコードで、コンテナを作成できます。

```py
# コンテナの作成
container_client = blob_service_client.create_container('作成するコンテナの名前')
```

### ファイルのアップロード
```py
# ファイルのアップロード
blob_client = blob_service_client.get_blob_client(container='アップロード先のコンテナの名前', blob='アップロード先でのファイルの名前')
with open('アップロードするファイルのパス', 'rb') as uploaded_file:
    blob_client.upload_blob(uploaded_file)
```

### ファイルのダウンロード
```py
# ファイルのダウンロード
blob_client = blob_service_client.get_blob_client(container='ダウンロード元のコンテナの名前', blob='ダウンロードするファイルの名前')
with open('ダウンロード先でのファイルのパス', 'wb') as downloaded_file:
    downloaded_file.write(blob_client.download_blob().readall())
```

### コンテナの削除
コンテナにアップロードしたファイルを全て削除しなくても（メソッド内で削除しているかもしれませんが）、コンテナを削除できます。

```py
# コンテナ削除
container_client = blob_service_client.get_container_client('削除するコンテナの名前')
container_client.delete_container()
```

## GCP CloudStorage
### 事前準備
#### 接続情報の設定
接続情報として、サービスアカウントというクラウドストレージにアクセスするためのアカウントのキー（**サービスアカウントキー**）が必要になります。

[こちら](https://sleepless-se.net/2018/05/22/googlecloudstorage%E3%81%A7python%E3%81%8B%E3%82%89%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%82%92%E3%82%84%E3%82%8A%E3%81%A8%E3%82%8A%E3%81%99%E3%82%8B%E6%96%B9%E6%B3%95/#API) を参考に、サービスアカウントキーを作成して、サービスアカウントキーのJSONファイルをダウンロードします。

以下のコマンドで、環境変数にサービスアカウントキーを設定します。

```sh
$ export GOOGLE_APPLICATION_CREDENTIALS="ダウンロードしたJSONファイルのパス"
```

#### モジュールのインストール
**google-cloud**をインストールします。

```sh
$ pip install --upgrade google-cloud
```
以降のGoogle CloudStorageに対する各操作をする上で、以下のコードで作成した**storage_client**がベースになります。

```py
from google.cloud import storage

storage_client = storage.Client()
```

### バケットの作成
GCP CloudStorageにおいて、ファイルを格納する箱は**バケット**と呼ばれます。
以下のコードで、バケットを作成できます。

```py
# バケットの作成
bucket = storage_client.create_bucket('作成するバケットの名前')
```

### ファイルのアップロード
```py
# ファイルのアップロード
bucket = storage_client.get_bucket('アップロード先のバケットの名前')
blob = bucket.blob('アップロード先でのファイルの名前')
blob.upload_from_filename(filename='アップロードするファイルのパス')
```

### ファイルのダウンロード
```py
# ファイルのダウンロード
bucket = storage_client.get_bucket('ダウンロードするファイルがあるバケットの名前')
blob = bucket.blob('ダウンロードするファイルの名前')
blob.download_to_filename('ダウンロード先のファイルのパス')
```

### バケットの削除
```py
# バケットの削除
bucket = storage_client.get_bucket('削除するバケットの名前')
bucket.delete(force=True)
```
（AWS S3と同様に）バケットを削除するためには、バケットにアップロードしたファイルを全て削除して空っぽにしておく必要あります。
バケットが空っぽでない状態でバケットを削除しようとするとエラーになって削除できません。

**force=True**にすることで、バケットを空っぽにした上でバケットを削除します。

ちなみに、ファイルの削除は以下のようになります。

```py
# ファイルの削除
bucket = storage_client.get_bucket('削除するファイルがあるバケットの名前')
blob = bucket.blob('削除するファイルの名前')
blob.delete()
```

## 参考ページのリンク
- AWS S3
 - [AWSアクセスキー作成
](https://qiita.com/miwato/items/291c7a8c557908de5833)
 - [Boto3 Docs](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/s3.html)
 - [Python boto3 でAWSを自在に操ろう ~入門編~](https://qiita.com/kimihiro_n/items/f3ce86472152b2676004)
 - [AWS S3にPythonで画像ファイルアップロードする方法](https://qiita.com/tottu22/items/0b3dd3e61f79fdba1145)
- Azure Blob Storage
 - [クイックスタート: Python用AzureBlobStorageクライアントライブラリ](https://docs.microsoft.com/ja-jp/azure/storage/blobs/storage-quickstart-blobs-python)
 - [github.com/Azure/azure-sdk-for-python](https://github.com/Azure/azure-sdk-for-python/tree/master/sdk/storage/azure-storage-blob)
- GCP Cloud Storage
 - [GoogleCloud: 認証の開始](https://cloud.google.com/docs/authentication/getting-started?hl=ja)
 - [CloudStorage: 入門ガイド](https://cloud.google.com/storage/docs/how-to)
 - [Google Cloud Client Libraries for Python](https://googleapis.dev/python/storage/latest/client.html)
 - [GoogleCloudStorageでPythonからファイルをやりとりする方法](https://sleepless-se.net/2018/05/22/googlecloudstorage%E3%81%A7python%E3%81%8B%E3%82%89%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%82%92%E3%82%84%E3%82%8A%E3%81%A8%E3%82%8A%E3%81%99%E3%82%8B%E6%96%B9%E6%B3%95/)