Python3からCloud Storageを利用(入門)

# はじめに
## BytesIOとは
BytesIOとは、メモリ上でバイナリデータを扱うための機能であり、Python の標準ライブラリ io に含まれています。バイナリデータとは主に画像や音声などのデータのことを示しています。(C#でいうMemoryStreamのようなものです)

# サービスアカウントの作成
[Google Cloud Platform](https://console.cloud.google.com/)にアクセスしてサービスアカウントの作成（API）を行います。
ナビゲーションメニュー > APIとサービス　> 認証情報 をクリックし画面に移動します。
そしてサービスアカウントを管理をクリックします。
![GCP.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/817075/18512082-f5d6-4f93-faa8-bb2ddaaa26be.png)

次の画面ではサービスアカウントを作成をクリックします。
![GCP.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/817075/252ccae4-220b-ad61-4b18-5971d51dc04a.png)
サービスアカウントの詳細を各項目入力していきます。

|設定項目  |設定内容  |
|---|---|
|サービス アカウント名|（任意の名前に設定） |
|サービスアカウント説明|（各プロジェクトわかりやすいように任意で設定） |
入力が終了したら作成をクリックします。
![スクリーンショット 2020-10-31 20.24.32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/817075/50d378e2-8357-8350-19da-50ee45ff25a5.png)
次の項目ではCloud Storageに関するロールを作ります。今回はテストなので`ストレージ管理者`(フル権限)を選択しました。
使用アプリケーションに応じてロールを変更するようにしましょう。
![スクリーンショット 2020-10-31 20.25.59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/817075/f4d3a526-3045-3605-5c04-6d4aaee98a49.png)

最後の項目は省略して大丈夫です。
作成したサービスアカウントをクリックし、キーの項目で鍵を追加をクリックし新しい鍵を作成を選択します。
![スクリーンショット 2020-10-31 20.00.44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/817075/d5523faa-98f7-7c18-74fc-f3467058f99e.png)

![GCp.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/817075/e79af6aa-2f4e-bafb-7517-290f0ee0a04d.png)

キーのタイプはJSONを選択して「作成」します。ローカルストレージ内にJSONファイルがダウンロードされるので次の項目でそのJSONファイルを使用し、PythonからCloud Storageを操作していきます。

# PythonからCloudStorageを操作

## Pythonライブラリーのインストール
今回のプロジェクトで必要なライブラリーを順番にインストールしていきます。
まずCloud Storageにアクセスするために、pip install で Google Cloud Storage のライブラリーをインストールを行います。

```
pip install google-cloud-storage
```
BytesIOを経由して Pillowを使いローカル上にファイルに保存するためPillowもインストールしていきます。

```
pip install requests pillow
```

Excelファイルなども試したい方向け、openpyxlのインストール

```
pip install openpyxl
```

## Cloud Storage上のバケットの準備

GUIからGoogle Cloud Storageにアクセスし、バケットを作成し適当な画像ファイルを準備します。
コンソール画面から　ナビゲーションメニュー >　Cloud Storage　で移動します。
今回はPythonのロゴファイルをダウンロードし、image.pngという名前をつけ保存しました。
[Pythonのロゴファイル](https://www.python.org/static/img/python-logo@2x.png)
![スクリーンショット 2020-10-31 20.53.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/817075/66b167e6-2b9f-6067-412d-e7bb45bb5fd7.png)

## PythonからCloud Storageにアクセスし画像を取得
最初の方で作成したアクセスユーザのキーを使いCloud Storageにアクセスをしていきます。
まず最初にアクセスユーザのキーを読み込ませる必要があります。２通りのアクセスの参照の仕方を記載します。

```
# 環境変数を使用しアクセスする場合
import os
os.environ['GOOGLE_APPLICATION_CREDENTIALS'] = '{jsonファイルが置かれているパスを記入}'
client= storage.Client()

# 直にjsonファイルへアクセスする場合。
client = storage.Client.from_service_account_json('{jsonファイルが置かれているパスを記入}')
```

Google Cloud Storage（GCS）に保存した画像ファイルを取得し、ローカル上にファイルを保存するPythonのコードになります。
プログラムがやっている説明として、ファイルを保存したいbucketと保存ファイル名のblobインスタンスを取得します。
画像のバイナリデータが入っているのでBytesIOを経由してPillowで読み込み、任意の画像ファイルをして書き込む流れになります。
`blob.download_to_filename`　<strong color="rgb(255,0,0)"><font color="Red">を使うことによってファイルをGCSから直接ダウンロードしたりすることもできますが、今回はGCSから落としたファイルに対して編集などを加えたりする想定でPILライブラリーなどにデータを渡す形にしています。</font></strong>


```
from google.cloud import storage
from PIL import Image
import io

#google cloud storageのクライアントインスタンスを作成
#client = storage.Client()
client = storage.Client.from_service_account_json('●●●●●●●●●●.json')
#バケットのインスタンスを取得
bucket = client.bucket('{任意の名前で作成したバケット名}')

#ファイルのblobインスタンスを取得
blob = bucket.blob('image.png')
img = Image.open(io.BytesIO(blob.download_as_string()))
img.save('sample.png')
```

## PythonからCloud Storageにアクセスしエクセルファイルを取得
GCS上のエクセルファイルを取得しそのBlobデータをBytesIOを経由してopenpyxlで読み込み保存します。
`blob.download_to_filename`　<strong color="rgb(255,0,0)"><font color="Red">を使うことによってファイルをGCSから直接ダウンロードしたりすることもできますが、今回はGCSから落としたファイルに対して編集などを加えたりする想定でPILライブラリーなどにデータを渡す形にしています。</font></strong>

```
from google.cloud import storage
import openpyxl
import io

#google cloud storageのクライアントインスタンスを作成
client = storage.Client.from_service_account_json('●●●●●●●●●●.json')
#バケットのインスタンスを取得
bucket = client.bucket('{任意の名前で作成したバケット名}')

##ファイルのblobインスタンスを取得
blob = bucket.blob('test.xlsx')
buffer = io.BytesIO()
blob.download_to_file(buffer)
wb = openpyxl.load_workbook(buffer)
wb.save('./retest.xlsx')
```


# 参考にさせていただいた記事
・[Cloud Storageの画像をリサイズして再アップロードする - Qiita](https://qiita.com/tfuruya/items/f0f435bc7abe965f6359)
・[【Python】 バイナリデータの画像を扱う | かずさプログラマーの雑記帳](https://kazusa-pg.com/python-binarydata-picture/)
・[Python で Google Cloud Storage と、BigQuery を使う過程でのエラー | Monotalk](https://www.monotalk.xyz/blog/python-%E3%81%A6-google-cloud-storage-%E3%81%A8bigquery-%E3%82%92%E4%BD%BF%E3%81%86%E9%81%8E%E7%A8%8B%E3%81%A6%E3%81%AE%E3%82%A8%E3%83%A9%E3%83%BC/)
・[Python - GCP Cloud Functions(Python)でCloud Storage上のExcelファイルを編集したい｜teratail](https://teratail.com/questions/225524)
・[PythonでOpenPyXLを使ってExcelファイルの新規作成・保存を行う方法](https://tonari-it.com/python-openpyxl-beginner-make-excel/)
・[BytesIO（およびStringIO、cStringIO）の使い方【初心者向け】 | TechAcademyマガジン](https://techacademy.jp/magazine/19185)
・[Pythonでオンメモリストリームを利用して、中間データを保存せずファイルを扱う | hgrs's Blog](https://blog.hgrs.me/20190525231834)
・[pythonでGoogle Cloud Storageへアクセスしてファイルをアップロード/ダウンロードする方法｜ドドテクノ](https://dodotechno.com/python-gcs/)
・[【Python】 バイナリデータの画像を扱う | かずさプログラマーの雑記帳](https://kazusa-pg.com/python-binarydata-picture/)