はじめに
前回「スプレッドシートをGoogleドライブにCSV出力する」ということで、PythonでスプレッドシートとGoogleドライブを操作するまでの流れを紹介しました。
今回は、そのプログラムをAWS Lambdaで定期実行することにより、システム連携やバックアップなどで運用負荷を低減する方法を紹介します。
また、今回Lambdaファンクションの開発環境としてCloud9を使用しますが、Cloud9の仕様も大きく変わっていました。新しいCloud9でLambdaファンクションを作るときにも是非参考にしてもらえたら嬉しく思います。
※ PythonでスプレッドシートやGoogleドライブを操作するまでの流れは、以下の記事で紹介しています。ファンクションの動作自体はこちらの内容が前提となっていますので、以下の内容も併せて読んでみてください。
スプレッドシートをGoogleドライブにCSV出力する
PythonでスプレッドシートやGoogleドライブを操作するまでの流れや、Pythonのサンプルプログラムを紹介しています。構築手順を参考にしてください。
今回の流れ
今回は全体の流れが掴みにくいので、まずおおまかな流れを紹介します。作業をする際に何のために何の作業をしているのか把握して行ってもらえたらと思います。
- AWS Lambdaのひな形作成
まずはAWS Lambdaのブランクファンクションを作成します。以前はCloud9上からブランクファンクションを作成できたのですが、Cloud9の仕様が変わったため、
AWSコンソールからファンクションの作成を行います。Lambdaの実行環境はPython3.9とします。
- Cloud9の作成
Lambdaファンクションの開発環境としてCloud9を使用するため、Cloud9の作成を行っていきます。
- Cloud9のPythonを3.9に変更
LambdaをPython3.9で動かすので、開発環境もバージョンを合わせるようにします。
- Cloud9上にLambdaファンクションをダウンロード
作成したブランクファンクションをCloud9上にダウンロードし、開発できるようにします。
- 使用するPythonライブラリのインストール
プログラムで使用するライブラリをインストールします。
- Lambdaファンクションの作成・テスト
Lambdaファンクションを作成します。作成後にCloud9上でテストを行います。
- Lambdaファンクションのデプロイ・動作設定
完成したLambdaファンクションをデプロイし、Lambdaの動作設定を行います。
AWS Lambdaのひな形作成
まずは、AWS Lambdaのひな形としてブランクファンクションを作成するところから始めます。
以前はCloud9上から作成できたのですが現在はSAMアプリケーションしか作成できなくなっており、何もない空のファンクションを作成できなくなっているみたいです。
AWSコンソールを開き、Lambdaサービスに移動し「関数の作成」をクリックします。
「関数名を適当に入力」し、「ランタイムをPython3.9」にして「関数の作成」をクリックします。
これで以下のようなシンプルな関数が作成されているはずです。
Lambdaのひな形作成は以上です。続けてCloud9を作成します。
Cloud9の作成
続いてLambdaの開発環境となるCloud9を作成します。Cloud9ではLambdaのテストやデプロイが簡単なので開発環境としてオススメです。
AWSコンソールのCloud9サービスを開き、「Create environment」から新しいCloud9を立ち上げます。
インスタンス名は適当に設定し、新しいEC2を立ち上げる(Create a new EC2…)でいいかと思います。インスタンスのタイプは、t2.microだとさすがにスペックが低い気がするので、t3.smallかm5.largeあたりにします。
OSはAmazon Linux2で問題ありません。
これでCloud9の画面が立ち上がったはずです。
Cloud9のPythonを3.9に変更
続いてLambdaのPythonのバージョンとCloud9のPythonのバージョンを合わせます。
LambdaはPython3.9ですが、Cloud9は立ち上げたときにはPython3.7となっています。そこで、pyenvをインストールし、Python3.9に変更します。
今回こちらのQiita記事を参考にバージョン変更を行いました。
$ #■ pyenvをダウンロード
$ git clone https://github.com/pyenv/pyenv.git ~/.pyenv
$ #■ ~/.bashrc に以下を追記してパスを通す
$ vi ~/.bashrc
===================================
export PATH="$HOME/.pyenv/bin:$PATH"
eval "$(pyenv init -)"
===================================
$ #■ .bashrcの変更を適用
$ source ~/.bashrc
$ #■ pyenvにパスが通ったことを確認
$ pyenv --version
$ #■インストールできるPythonのバージョンを確認
$ pyenv install --list
$ #■3.9.XならOKなので、今回は3.9.5を選択
$ pyenv install 3.9.5
$ pyenv global 3.9.5
$ #■Pythonのバージョンが変わっていることを確認
$ python --version
以上の流れでPythonのバージョンを確認し、3.9.5になっていれば完了です。
Cloud9上にLambdaファンクションをダウンロード
Cloud9上に作成したLambdaファンクションをダウンロードし、開発できるようにします。
Cloud9左側のAWSマークからLambdaを選択し、作成したファンクションを右クリックし、Downloadからファンクションをダウンロードします。
ダウンロードしたら、左側のディレクトリマークからLambdaファンクションがディレクトリとしてダウンロード出来ていることを確認します。
使用するPythonライブラリのインストール
今回使用するPythonのライブラリをインストールします。
ポイントは、ダウンロードしたLambdaのディレクトリ配下にライブラリをインストールすることです。
そうしないと、Lambdaの実行ファイルにライブラリも含むことができません。
$ #■Lambdaファンクションのディレクトリに移動
$ cd ~/gsheet-to-gdrive
$ #■pipの更新
$ pip install -U pip
$ #■ライブラリのインストール
$ pip install gspread --target ./
$ pip install pydrive --target ./
$ pip install oauth2client --target ./
$ #■ライブラリの更新
$ pip install -U oauth2client google-api-core google-auth google-api-python-client --target ./
今回使いたいgoogle-api-coreやgoogle-authはバージョンが合わないとうまく動作しないため、念のためライブラリの更新も行っています。
Lambdaファンクションの作成・テスト
下準備が整ったので、いよいよLambdaファンクションにコードを書いていきます。
先ほどダウンロードしてきたlambda_function.pyを以下のように編集します。
import gspread
import csv
import json
from pydrive.auth import GoogleAuth
from pydrive.drive import GoogleDrive
from oauth2client.service_account import ServiceAccountCredentials
ACCESS_KEY_JSON = "XXXX" ##先ほどダウンロードしたjson鍵ファイル
SPREAD_SHEET_KEY = "XXXX" ##スプレッドシートキー
GOOGLE_DRIVE_ID = "XXXX" ##Google Driveキー
worksheetname = "シート1" ##出力するシート名
filename = 'XXXX.csv' ##Google Driveに出力するcsvファイル名
def lambda_handler(event, context):
## Google SpreadSheet からCSVをダウンロード
credentials = ServiceAccountCredentials.from_json_keyfile_name(ACCESS_KEY_JSON, ['https://spreadsheets.google.com/feeds','https://www.googleapis.com/auth/drive'])
spreadsheet = gspread.authorize(credentials).open_by_key(SPREAD_SHEET_KEY)
worksheet = spreadsheet.worksheet(worksheetname)
with open("/tmp/"+filename, mode='w', newline='', encoding='shift_jis') as f:
writer = csv.writer(f)
writer.writerows(worksheet.get_all_values())
## Google Driveへのアップロード
gauth = GoogleAuth()
scope = ["https://www.googleapis.com/auth/drive"]
gauth.credentials = ServiceAccountCredentials.from_json_keyfile_name(ACCESS_KEY_JSON, scope)
drive = GoogleDrive(gauth)
file = drive.CreateFile({"title": filename , 'mimeType': 'text/csv', "parents": [{"id": GOOGLE_DRIVE_ID}]})
file.SetContentFile("/tmp/"+filename)
file.Upload()
※ 今回はgspreadとpydriveを使用して、スプレッドシートをGoogleドライブにcsv出力しようとしています。これらのライブラリを使うためにはGoogle APIなどの下準備が必要です。上記コードを実行する際は、以下の記事も併せて参照ください。
スプレッドシートをGoogleドライブにCSV出力する
PythonでスプレッドシートやGoogleドライブを操作するまでの流れや、Pythonのサンプルプログラムを紹介しています。構築手順を参考にしてください。
また、独自の環境に合わせて、以下の変数を変更してください。
(変数の意味が分からない場合は上記記事を参考にしてください。)
- ACCESS_KEY_JSON:先ほどダウンロードしたjson鍵ファイル名
- SPREAD_SHEET_KEY:スプレッドシートのキー
- GOOGLE_DRIVE_ID:Google Driveのキー
- worksheetname:出力するスプレッドシートのシート名
- filename:Google Driveに出力するcsvファイル名
コードが記載出来たら、認証で使用するjsonファイルもLambdaファンクションのフォルダにアップロードしてください。
ここまで出来たら、あとは動かすだけです。
「Auto」と書いてある部分から、プルダウンで実行したいファンクション名を選択し、「Run」で動作させてください。
Cloud9下部の実行ログで、エラーが出ておらず以下のようになっていれば特に問題なかったということになります。成功していれば、設定したGoogleドライブにcsvが出力されていると思います。
Lambdaファンクションのデプロイ・動作設定
動作確認まで出来たら、あとはデプロイしてLambdaの実行設定をするだけです。
Cloud9左側のAWSマークからLambdaを選択し、作成したファンクションを右クリックし、Upload Lambda…からファンクションをデプロイします。タイプは「ZIP Archive」でBuild directoryは「No」を選択します。最後に確認が出るので、「Yes」を選択すれば完了です。
本当にデプロイできたかAWSコンソールのLambdaサービスから確認します。
更新が40秒前なので、デプロイできていることがわかります。
あとは動作設定を調整して完了です。特にタイムアウトは初期3秒なので、増やす必要がありそうです。
Lambdaサービスの「設定」から「編集」をクリックし、メモリとタイムアウトを変更します。
最初は多少多めにしておきます。
あとは「テスト」からテストしてみて、所要時間や使用中の最大メモリを見て先ほどの設定項目を微調整します。
また、テストを実行したらGoogleドライブにcsvが出力されるはずなので、本当に出力されているかチェックするといいでしょう。
また、作成したLambdaを定期実行したいなら、「トリガーを追加」から「Event Bridge」を選択し、「新規ルールの作成」でCron式を入力することで、定期的に実行させることができます。
おわりに
前回紹介したスプレッドシートをGoogleドライブに出力するプログラムをAWS Lambdaで動かす手順を紹介しました。
今回の手順はプログラム自体違っても、Lambda構築の基本的な流れは変わらないのでいろいろな場面で応用が利きます。
Lambdaファンクションは標準搭載しているライブラリ以外に新しいライブラリを使いたい場合は今回のような手順を踏んで作成していくことになるかと思いますので、手順を忘れたときなどに振り返って参考にしてもらえたら嬉しく思います。