PythonからGAS(Google Apps Script)関数を呼び出すためのメモ。
目標
GAS関数を利用してGoogleAPIを一本化しよう!
下準備
読者がどれくらいGoogleサービスに慣れているかわからないが、一から全てを記述していては日が暮れてしまうため、以下の項目については各自でGoogleしてほしい。
- Google Apps Scriptプロジェクトの作成方法
- claspによるGoogle Apps Scriptのローカル開発
- Google Cloud Platformのプロジェクト作成方法
- Google Cloud PlatformでAPIを使用するためのOAuth2.0クライアントIDの取得
- Google Apps Scriptのプロジェクトを実行可能APIとしてデプロイする
きっと良い記事が見つかることだろう。
以下ではGASでsendEmail()
という次の関数を実行可能APIとしてデプロイしたと仮定して進める。
/* これはTypeScriptで書いているため、GASで動かすためには型を取り除く必要がある */ function sendEmail(recipient: string, subject: string, body: string) { MailApp.sendEmail( recipient, subject, body ) }
Python から GAS関数を実行する
ライブラリのインストール
Googleが提供しているOAuth2.0およびAPIを呼び出しやすくするためのライブラリをインストールする。
$ pip install google-auth google-auth-oauthlib google-api-python-client
よくチュートリアルにあるoauth2client
はdeprecatedとなっている(accessed on 2021/12/4)ため使用しない。Googleもドキュメントを書き換えるべきだが忙しいのだろうか。
Credentialsの取得
よくわからなくてもコピペすれば動くのがチュートリアルコードであるが簡単に解説すると、
- Credentialsはユーザが同意したGoogleリソースにアクセスするための資格情報である
- Credentialsはファイルに保存して再利用することが出来る
- Credentialsが期限切れでリフレッシュトークンがある場合はリフレッシュできる
- リフレッシュトークンがない場合やそもそもCredentialsが存在しない場合はOAuth2.0フローを通して資格情報を取得する
- scopeとはアプリケーションが利用するGoogleリソースの範囲・権限である
client_secret.json
はGoogle Cloud PlatformのAPIとサービス→認証情報→OAuth2.0クライアントというところから取得する(ググって)。
import os from typing import Optional from google.auth.transport.requests import Request from google.oauth2.credentials import Credentials from google_auth_oauthlib.flow import InstalledAppFlow CLIENT_SECRET_FILE = 'client_secret.json' TOKEN_FILE = 'token.json' SCOPES = [ 'https://www.googleapis.com/auth/script.scriptapp' # 今回はメールを送信する関数しか呼び出さないのでこのスコープだけ 'https://www.googleapis.com/auth/script.send_mail' ] def get_credentials() -> Credentials: credentials: Optional[Credentials] = None if os.path.exists(TOKEN_FILE): credentials = Credentials.from_authorized_user_file(TOKEN_FILE, scopes=SCOPES) if credentials and credentials.valid: return credentials if credentials and credentials.refresh_token: credentials.refresh(Request()) # リフレッシュトークンが期限切れのこともあるのでエラーハンドリングすべき return credentials flow = InstalledAppFlow.from_client_secrets_file( CLIENT_SECRET_FILE, scopes=SCOPES ) credentials = flow.run_console() return credentials def save_credentials(credentials: Credentials) -> None: with open(TOKEN_FILE, 'w') as f: f.write(credentials.to_json())
Credentialsを取得するフローはAPIを叩くなら必ず必要なので、ライブラリにするかスニペットに登録するか記憶に叩き込む。
GAS関数を呼び出す
準備が整ったのでGASの関数を呼び出す関数を実装する。
from typing import Any from googleapiclient import discovery GAS_DEPLOY_ID = 'hogehoge' # Google Apps Script の実行可能APIのデプロイID def call_function( func_name: str, parameters: Optional[list[str]] = None ) -> Any: body: dict[str, Any] = { 'function': func_name, } if parameters: body['parameters'] = parameters script_service = discovery.build( 'script', 'v1', credentials=get_credentials() ) response: Any = script_service.scripts().run( scriptId=GAS_DEPLOY_ID, body=body ).execute() # JavaScriptのオブジェクトをJSON化してPythonのdictにしたものが返ってくる return response.get('response').get('result')
googleapiclient
ライブラリの使い方は3つくらいのAPIのドキュメントを読めば共通点がつかめる。
googleapiclient.discovery.build()
で使用するAPIのインスタンスを作成- インスタンスにメソッドチェーンでAPIのパスを構築
- 引数はドキュメントを読みながら実装
- 最後に
execute()
メソッドを呼び出してレスポンスを受け取る - レスポンスの中身もドキュメントを見ないとわからない
developers.google.com (accessed on 2021/12/4)
最後にcall_function()
を使用してGASのsendEmail()
を呼び出してみる。
recipient = 'foo@example.com' subject = 'Test Calling GAS function' body = 'Success!' parameters = [recipient, subject, body] call_function(func_name='sendEmail', parameters=parameters)
無事メールが送信されれば成功。
応用案
今回はメールを送信するだけだったので直接GmailのAPIを叩いてもよかった。 しかし、一度GASを通すという今回の実装はGoogleの複数のAPIを利用するときに真価を発揮する。
例えば次のような一連の処理
をPython上で実装すると3回HTTP通信を行わなければならない。GASで実装すれば一つのAPI呼び出しだけで終わる。
「全部GAS上でやれば?」というのはもっともな指摘であるが、今回は処理にSeleniumをかませる必要があったのでGAS環境外のリソースを使う必要があったのだ。
GASについて
Google Apps ScriptはGoogleのリソースを使ってスクリプトを実行できるサービスである。 ベースにはJavaScriptが採用されていて、claspというGoogle製のコマンドラインツールを使用すればローカル環境でTypeScriptを使って開発することが出来る。 1日に使用できるAPI呼び出しや外部アクセスに対して制限(accessed on 2021/12/4)が存在するが、個人で使用する分や小規模サービスであればそれほど問題にはならない。
github.com (accessed on 2021/12/4)
Google Apps Scriptを使用する理由として以下のが挙げられる。
- 他のGoogleサービスとの連携が容易
- Googleのリソースを使用することができる
- ベースがJavaScriptなので気軽に始められる
GoogleはAPI提供に積極的であるため、どんな言語(Node.js, Python, Go, C#, 単純にHTTPリクエスト)でも容易にAPIを叩くことが出来る。GmailとGoogle SpreadSheetsとGoogle Driveを連携したシステムを構築したいとなった際、これらの言語で各APIを叩くこともできるが、GAS上で各サービスのAPIを呼び出してGoogleの通信リソースを借用することで自身の通信リソースを節約することが出来る。
おわりに
PythonからGoogle APIの呼び出しをGASを使って一本化するというのは、本当はclaspを使ってTypeScriptでがっつりGASのローカル開発環境を整えてからでないと意味がない。
しかしながら、自分はまだTypeScript初心者であるし(jest
もやっとのことで導入できた。。。)、先人がいくつか記事を残してくれていたので今回は詳しく触れないことにする(記憶用の簡単なメモは書くかもしれない)。この記事を読んで「claspなんてあるのか」とか「google-authなんてライブラリがあったのか」と思ってGoogleするきっかけになれば私も嬉しく思う。
このようにGoogleはAPIと自社のリソースをエンドユーザにさえ積極的に公開して、世の中のAutomationや業務効率化が進むように貢献している。 それに比べて日本の企業は「我が社にすべてお任せください!」という姿勢ばかりで、自社のリソースをエンドユーザに公開することなど一切ない。
先日MLサービスを比較しようとして、どことは言わないが日本の企業のサイトも見に行ってみた。 驚いたことにサービスの紹介ばかりでチュートリアルなどは一切なく、最後に「資料請求はこちらから」と書いてあったのは爆笑してしまった。 完全に組織のネームバリューに依存したマーケティング戦略で、ユーザにサービスをお試しで使ってもらって競合サービスとの差を実感してもらおうという姿勢が全く見られない。
10か月前ほどにGoogleはmodel_search
という機械学習のハイパーパラメータを遺伝的(mutation)アルゴリズムによって最適化するライブラリを公開した。
github.com (accessed on 2021/12/4)
Apache2.0ライセンスのもと使用できるオープンソースプロジェクトである。コントリビュータはたったの2人!
ただでさえ重いニューラルネットワーク学習タスクに遺伝的アルゴリズムを加えて計算機パワーでAIエンジニアの仕事を奪う楽にするという素晴らしいライブラリだ。
もちろんこんなものエンドユーザのローカル環境で動かせるはずもなく、中小企業でも難しいと思われる。
当然Googleはビジネスが上手いので、自社のクラウドコンピューティング環境を実行環境として提供している。
という社会も企業も研究者も得するサイクルがそこには存在する。 日本の企業で新技術をライブラリとして公開しているとかLinuxディストリビューションを頒布しているとかあったら教えてください。就活の参考にします。 脆弱性対応の分野では結構進んでいる方だと思うけれど、脆弱性潰しても儲からん。。。
確か先月あたりにMicrosoftもAutoMLのライブラリを公開していた。名前は忘れた。