見出し画像

PythonとGoogle Spreadsheetで家庭菜園の収穫管理 ~ (前) 認証編

後編はこちら

前置き

数年来、家庭菜園の収穫数の管理(まあ有り体に言って閲覧だけですが)をGoogle Spreadsheetでやっていました。植え付けの情報を書き込んだり、収穫数を記録したり。そして、グラフで各年を比べながら「ほう今年はナスが調子がいいぞ」とか「オクラは今月で終わりだな」とかやりたい、そしてグラフにはmatplotlibを使いたかったため、PythonからGoogle Spreadsheetへアクセスしていました。

が、たぶん、MacのOSをCatalinaにしたタイミングでAnacondaのインストールがやり直しになって、そこでいくつかのライブラリがmissingになって動かなくなってしまった…。

from apiclient.discovery import build
from httplib2 import Http
from oauth2client import file, client, tools

このあたりですかね。Anacondaでライブラリをインストールし直せば話が終わったはずなのですが…

ValueError: Client secrets must be for a web or installed app.

動かなくなりました。しょうがないなぁ・・・まあ、最近oauth2の仕組みを覚えたので、他のAPIで使う予定のrequestsライブラリが使るかなとか、ライブラリ回りスッキリさせたいなと思って、とりあえずご本尊のサンプルファイルをもう一度見に行きました。

あれ?なんか使ってるライブラリ違うし…複雑になってる…こりゃちょっと厄介だな。

とりあえず先人の知恵を拝借する〜サービスアカウントを使用する方法

まず、検索して良さそうと思ったこの記事のやり方を試してみましょう。

なにやら、「サービスアカウント」というのを作成すると、特別なメールアドレスが生成され、このアドレスに紐付いた秘密鍵をJSONで落として、gspread.authorize(credentials)で食わしてやると、シートにアクセスできますよ、というもの。なるほど、言われたとおりやったらサンプルファイルは動いた。

1. なんとかoauth2を使いたい

先日せっかくoauth2のトークンの使い方を勉強したので、そっちでやってみたい。あと結果的にコードがスッキリするので、この方法を使っていきたい。参考文献はこちら

途中までは上記Quiitaの手順と同じであるが、今回は「サービスアカウント」ではなく「Oauth 2.0 Client」を追加する。Google Cloud Platformの課金とかどうなっているのか全然分からないけど、APIを何億回も使わないかぎり、今回使用する程度の負荷量であれば無料の範囲のはず。

1-1. https://console.cloud.google.com/ から新規プロジェクトを作成。
1-2. Google Drive APIを有効にする。
1-3. Google Sheets APIを有効にする。
ここまでは一緒なので上記Quiita記事を参考にしてください。

1-4. 認証情報を設定する。
ここから手順が変わってくる。

1-4-1. プロジェクトのOAuth consent screenを設定
APIs& Services / Credentialsの「+」からOAuth client IDを選択。

画像6

「慌てんな、まずはOAuth consent screen作れや」と言われて、そっちに飛ばされる。ここで作る認証画面でアクセス許可してあげると、その認証に対応したトークン作成して返してくれるというのがOauth2の流れですね。

画像7

個人的にはInternalにしたいのだが、Organizationが適当なのでExternalにしかできないと怒られた。

画像8

App nameは適当。メアドは必要。ロゴは任意。

画像9

いろいろ聞かれるけどlocalhostでOKのはず。空白だとPythonコード実行時にエラーになる可能性がある。

画像10

次に許可するscopeの範囲を設定。凄く一杯scopeはあるので、"Sheets"でフィルターする。すると、全アクセスとリードオンリーアクセスとあるので、全アクセスを選んだ。

画像11

これで認証画面が作成された。

1-4-5. プロジェクトのOAuth2 Clientを作成
APIs& Services / Credentialsの「+」からOAuth client IDをもう一度選択。今度は認証画面作成済みなので、無事次へ進めた。ここでApplication typeはweb applicationにする。参考文献先では「Desktop appにしろ」と書いてあるが、これをやるとPython実行時に冒頭の"ValueError: Client secrets must be for a web or installed app."のエラーになる。

画像12

ようやくOAuth 2.0 Client IDが作成できた。そしたらこのダウンロードマークからclient_secret***.jsonをダウンロードする。この中にはoauth2のclient idやclient_secretが入っているので、人に見せたり共有したりせず保管する。

画像13

2. Pythonからアクセスしてみる。

2-1. gspreadライブラリのために、さきほどダウンロードしたclient_secret***.jsonを~/.config/gspread/credentials.jsonとしてコピー。

2-2. Spreadsheetを準備
お目当てのGoogle SpreadsheetのURLからIDをコピーしておく。

2-3. ここまでくるとコードは非常にシンプルになります。

import gspread

gc  = gspread.oauth()

sh = gc.open_by_key('YOUR SHEET ID')

print(sh.sheet1.get('A1'))

gcが接続のオブジェクトで、ここから先はgspreadのライブラリを用いてシートのセルにアクセスすることができます。その辺は「その2」で。

初めて実行する場合、認証ウィンドウが起動します。ところで、external属性の認証スクリーンなので、なんだかまずそうな画面になりますが(下図)

画像14

Uターンせずに勇気を出してContinueして、次の画面でもAllowします。

画像15

先のコードを実行してシートのA1セルの内容が表示されれば成功です。

画像11

イェィ!

認証プロセスで作成される、トークンを含むファイル~/.config/gspread/authorized_user.jsonの内容がcredentials.jsonと整合しない場合、コードの実行時にエラーがでる可能性があります。その場合は、元のファイルを消して上の認証プロセスを実行すればOKです。

うっ、うっ。久々に実行したら認証がexpireしているのか、実行できなかった。上記authorized_user.jsonを消去して、認証し直したら通るようになった。めんどくさいな。gspread.oauth()の行を以下のようにした。(2021/7/4追記)

# Setup the Sheets API
try:
   gsh_conn  = gspread.oauth()
except:
   fpath='~/.config/gspread/authorized_user.json'
   fname= os.path.expanduser(fpath)
   if os.path.isfile(fname):
       os.remove(fname)
   gsh_conn  = gspread.oauth()

またアクセスエラー。エラーが出るのはワークシートを取得するタイミングらしいので、それにあわせてgspread.oauth()まわりを再度改修。ちょっとダサいコード。(2021/8/1追記)

try:
   sh = gsh_conn.open_by_key(sheet_ID)
   # Obtain all the sheet object in a list
   worksheet_list = sh.worksheets()
except:
   print('Removing JSON file')
   fpath='~/.config/gspread/authorized_user.json'
   fname= os.path.expanduser(fpath)
   if os.path.isfile(fname):
       os.remove(fname)

   gsh_conn  = gspread.oauth()
   sh = gsh_conn.open_by_key(sheet_ID)
   # Obtain all the sheet object in a list
   worksheet_list = sh.worksheets()

ふぅ。ようやくこれでシートにアクセスできるようになった。次回、野菜の収穫まで行けるか?


この記事が気に入ったらサポートをしてみませんか?