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を選択。
「慌てんな、まずはOAuth consent screen作れや」と言われて、そっちに飛ばされる。ここで作る認証画面でアクセス許可してあげると、その認証に対応したトークン作成して返してくれるというのがOauth2の流れですね。
個人的にはInternalにしたいのだが、Organizationが適当なのでExternalにしかできないと怒られた。
App nameは適当。メアドは必要。ロゴは任意。
いろいろ聞かれるけどlocalhostでOKのはず。空白だとPythonコード実行時にエラーになる可能性がある。
次に許可するscopeの範囲を設定。凄く一杯scopeはあるので、"Sheets"でフィルターする。すると、全アクセスとリードオンリーアクセスとあるので、全アクセスを選んだ。
これで認証画面が作成された。
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."のエラーになる。
ようやくOAuth 2.0 Client IDが作成できた。そしたらこのダウンロードマークからclient_secret***.jsonをダウンロードする。この中にはoauth2のclient idやclient_secretが入っているので、人に見せたり共有したりせず保管する。
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属性の認証スクリーンなので、なんだかまずそうな画面になりますが(下図)
Uターンせずに勇気を出してContinueして、次の画面でもAllowします。
先のコードを実行してシートのA1セルの内容が表示されれば成功です。
イェィ!
認証プロセスで作成される、トークンを含むファイル~/.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()
ふぅ。ようやくこれでシートにアクセスできるようになった。次回、野菜の収穫まで行けるか?
この記事が気に入ったらサポートをしてみませんか?