Blow Up by Black Swan

Google Cloud FunctionsでPythonを使ってみる(Part.2 Cloud Functionsの様々な使い方)

前回、Google Cloud Functionsの基本的な使い方について、GCPコンソールから関数を作る方法やローカルマシンからデプロイする方法について記載しました。またそもそもの登録の仕方や関数作成までの流れについても参考サイトを紹介させて頂きました。

今回、少し応用を効かせた使い方について紹介していきます。サードパーティのパッケージや自作パッケージを利用したより拡張的な関数の作成と利用、グーグルスプレッドシートの連携など、実務的な使い方が色々とイメージ出来そうな内容かなと思います。一人でも多くの方の参考になれば幸いです。

Cloud Functionsについては3部作を予定しており、全体の内容は以下のようになっています。

Part1. Cloud Functionsの基本的な使い方: httpリクエストをトリガーとするHTTP functionの使い方、ローカルマシンからのデプロイ
Part2. Cloud Functionsの様々な使い方: サードパーティパッケージ、自作パッケージの利用、スプレッドシート(GAS)との連携
Part3. Seleniumを使ったスクレイピング
備考. background functionは対象外

1. デフォルト以外のパッケージの利用方法

前回紹介し、実際にデプロイしてみたコード例はGoogleが提供しているサンプルコードでした。Githubのリポジトリには多数のファイルが保存されていますが、最小限の構成はmain.pyの一つのファイルだけで成立します。また、Cloud Functionのpythonではflaskを基調とした構成になっており、標準モジュール以外にも複数のパッケージが入っていることも前回紹介しました。

一方で、現実にCloud FUnctionsを利用していく場合、他のモジュールなどを利用したい場合や自作パッケージを利用したい場合があります。この章では、Cloud Functionsではデフォルトでは入っていないパッケージの利用方法について説明しています。

1-1. サードパーティパッケージの利用

まずはサードパーティパッケージの利用方法です。GCPコンソールから関数を作るときにわかってしまうのですが、pythonでよく使うrequrements.txtに必要なパッケージ情報を記載するだけです(笑)。この場合の最小のファイル構成は以下のようになります。

myfunction/
  ├── main.py
  └── requirements.txt

requirements.txtに記載しておくだけで、関数のアップロード時に自動でこれらのパッケージをインストールし、環境を構築してくれます。あとは通常通りhttpトリガーならURLを叩いて使うだけです。

1-2. 自作パッケージの利用

自作パッケージについてはこちらも通常のpythonプログラムと同じ構成で、専用のフォルダを作成し”init.py”をファイルをその中に作成してあげるだけです。ファイル構成としては次のような構成になります。

myfunction/
  ├── main.py
  └── mypackage/
    	├── __init__.py
    	└── mymodule.py

init.py”は空白でも問題ありません。記載がなくともpythonは”init.py”ファイルが置いてあるフォルダを一つのパッケージとみなしてくれます。

1-3. 実際に使ってみる

それでは、実際にサードパーティパッケージと自作パッケージを使ってみます。フォルダ構成と各ファイルの記載事項は下記のようになっています。

フォルダ構成

# フォルダ構成
project
  ├──main.py 
	├──requirements.txt 
	└──test_package
			├──__init__.py
			└──test_p.py

test_package

“__init__.py”ファイルには何も記入していません。

from datetime import datetime

import pytz

def moscow_time(current_time):
    moscow_tz = pytz.timezone('Europe/Moscow')
    moscowTime = datetime.fromtimestamp(current_time, moscow_tz)
    return moscowTime

これはサードパーティパッケージのpytzを利用して、モスクワ時間を求める関数です。

main.pyとrequirements.txt

requirements.txtではpytzをインストールしています。

pytz

main.pyは下記のように記載されています。自作パッケージをインポートしています。

import time

from test_package.test_p import moscow_time

def display_moscowtime(request):
    current_time = time.time()
    current_moscow = moscow_time(current_time)
    return f"{current_moscow}です。”

自作パッケージやモジュールのインポートについては、下記の記事がよくまとまっていますので参考にして頂ければと思います。

デプロイと実行

これらをデプロイし、実行してみます。

$ gcloud functions deploy display_moscowtime --runtime python37 --trigger-http --region asia-northeast1

# デプロイ後
$ curl <デプロイ完了時に表示されるURL>

# 戻り値
2019-03-27 12:45:56.566389+03:00です。

オプションでクラウドサーバの地域を東京に指定しています。数分でデプロイが完了すると思いますが、完了後curlでurlにHTTPリクエストを送ると、関数実行時のモスクワ時間が返ってきます。この実験でサードパーティパッケージや自作パッケージが利用の仕方が理解できると思います。

2. Cloud Functionsとスプレッドシート(GAS)との連携

次はGoogleスプレッドシートとの連携についてです。ここではGASを間に挟んでスプレッドシートとCloud Functionsを連携します。

2-1. スプレッドシートとGAS

ご存知の方も多いと思いますが、GASとは正式名称Google App Scriptという、JavaScriptベースのプログラム実行環境のことです。私はGASしかわからないのですが、エクセルのVBAとほとんど同じなんじゃないかと思います。GASの使い方については、ここでは説明していませんが、下記のサイトのチュートリアルが非常にわかりやすいので、そちらで一通り使ってみて頂ければと思います。また、そのサイトを見て私が簡単にまとめたメソッド一覧も合わせて記載しておきます。

学習Tips
(1) Logger.log(format, value1, value2,...)
    ログ出力するメソッド
    formatは、pythonと同じ"%s"を利用
(2) Browser.msgBox(msg)
    ブラウザにメッセージダイアログを表示するメソッド

スプレッドシートに関わるTips
(1) オブジェクトの概念
    SpreadsheetApp...スプッレドシーに関わるトップレベルのオブジェクト
    スプレッドシートオブジェクト: Spreadsheet
    シートオブジェクト: Sheet
    セル範囲を表すオブジェクト: Range
(2) スプレッドシートの取得
    SpreadsheetApp.getActiveSpreadsheet()...AppScriptが結びついているスプレッドシートを対象のスプレドシートに指定するメソッドでSpreadsheetオブジェクトを生成する
    SpreadsheetOBJ.getName()...スプレッドシート名を取得するメソッド
(3) シートの取得
    SpreadsheetOBJ.getSheetByName(sheet)...シート名を取得してシートを取得するメソッド
    SheetOBJ.getName()...シート名を取得するメソッド
    SpreadsheetApp.getActiveSheet()...アクティブなシートを取得するメソッド
(4) セル範囲
    SheetOBJ.getRange(アドレス)...アドレス(A1:E5)で指定したセル範囲を取得。RangeOBJの生成
    SheetOBJ.getRange(行番号, 列番号)...対象のセルを取得。RangeOBJの生成
    SheetOBJ.getRange(行番号, 列番号, 行数, 列数)...セル範囲を指定する方法
    RangeOBJ.getValue()...単体のセルの値を取得するメソッド。範囲で指定されている場合でも一番左上の値だけが返される
    RangeOBJ.getValues()...二次元配列で指定したセル範囲の値を取得する
    RangeOBJ.setValue(値)...指定したセルに値を入力するメソッド。複数範囲であれば配列で指定すれば良い
    RangeOBJ.getA1Notation()...Rangeオブジェクトのアドレスを取得するメソッド
    RangeOBJ.clear()...セル範囲をすべてクリアにするメソッド
    RangeOBJ.clearContent()...コンテンツ(数式や値だけ)だけをクリアにするメソッド。背景色や罫線は消えない
    RangeOBJ.clearFormat()...書式をクリア
    RangeOBJ.clearDataValidations()...データの入力規則をクリア
    RangeOBJ.clearNote()...コメントをクリア
(5) スクレイピング関係
    UrlFetchApp.fetch(URL [,パラメータ])...HTTPリクエストを送るメソッド
    * パラメータ: header, method(HTTPメソッド), payload(POSTのボディ)
(6) その他メソッド
    SheetOBJ.getLastRow()...シートの最終行数を自動で取得するメソッド

2-2. スプレッドシートと連携してみる

スプレッドシートとの連携イメージは下図のように、スプレッドシートとGASを連携させた上でHTTP
functionを呼び出します。そして、返されたデータをGASで処理し、スプレッドシートに書き出す、という流れになります。今回は一つ前の章で作成したモスクワ時間を求める関数を呼び出し、それをスプレッドシートに書き込みます。

スプレッドシート-GAS -> HTTP function -> returned data -> GAS -> スプレッドシート

スプレッドシートとGASとの連携の一番簡単な方法は、スプレッドシートを開き、ツールバーの中から「ツール –
スクリプトエディタ」と選べば自動でスプレッドシートと連携したGASのエディタ立ち上がります。GASのプログラムは以下のようになります。この関数では、実行するとモスクワ時間を算出する関数の結果をスプレッドシートのA1セルに入力してくれます。

function myFunction() {
  var sheet = SpreadsheetApp.getActiveSheet();
  var range = sheet.getRange(1, 1);
  var res = UrlFetchApp.fetch("<HTTP functionのURL>");
  range.setValue(res);
}

スクリプトエディタの右向きの黒い三角ボタンを押すとプログラムが実行されます。ただし、1回目の実行時に信用できないアプリへのアクセスに関する注意喚起が出ることがありますが、これは詳細等から承認処理をしてしまって構いません。

cloud functionsとスプレッドシートの接続例1

プログラムの実行が成功するとA1セルに時間が表示されています。

cloud functionsとスプレッドシートの接続例2

3. Part2の終わり

以上がサードパーティパッケージや自作パッケージの利用方法とスプレッドシート、GASとの連携方法になります。他のパッケージを利用できるようになったり、スプレッドシート連携できるようにだけCloud Functionsの利用用途がかなり拡がると思います。GASではcronのように定時実行するように設定することもできるので、Cloud Functionsでスプレイピング用の関数やAPIを叩く関数を設置し、毎日定時に実行するようにしておいて、必要な情報をどんどんアップデートしていくといったこともできます。

この記事が読んだ方の参考になれば幸いです。読んで頂き、ありがとうございました。