認証なしで実行できるようにしようと思った背景
最近、スプレッドシートの数万のデータを扱うのにGASでは限界を感じていて、Colabで実行したら軽かったのでColabでのスプレッドシート操作が多くなってきました。
ですが、毎回下記の認証をするのが面倒だったので、認証なしで実行できる方法を実装しました。
!pip install gspread
from google.colab import auth
from oauth2client.client import GoogleCredentials
import gspread
# 認証処理
auth.authenticate_user()
gc = gspread.authorize(GoogleCredentials.get_application_default())
ss_id = 'スプレッドシートのID'
sht_name = 'シート名'
workbook = gc.open_by_key(ss_id)
worksheet = workbook.worksheet(sht_name)
Colabではなく、Pythonでスプレッドシートを操作するときは認証が必要ないので、
同じコードで実装できるようにしました。
Pythonでの実装方法は下記を参考にさせて頂きました。
JSONファイルを用意するための手順
詳細は上記記事を見た方がわかりやすいですが、簡易的な手順は下記となります。
① Spreadsheet API, Drive APIの有効化
https://console.cloud.google.com/apis/library/sheets.googleapis.com
https://console.cloud.google.com/apis/api/drive.googleapis.com
② 認証情報でサービスアカウントの作成し、JSONデータのダウンロード
https://console.cloud.google.com/apis/credentials
JSONデータをアプリケーションとして公開
Pythonで実装するときはダウンロードしたJSONファイルの場所を指定する必要があります。
しかし、Colabではローカルフォルダからデータの読み込みはできず、ドライブ上のファイルしか指定ができない上、
ドライブ上のファイルを指定するのにも認証が必要でした。
なので、認証に必要なJSONファイルはGASのアプリケーションから取得するようにしました。
function doGet(e) {
// ダウンロードしたJSONファイルをそのまま記載
const json = {
"type": "service_account",
"project_id": "",
"private_key_id": "",
"private_key": ""
"client_email": "",
"client_id": "",
"auth_uri": "https://accounts.google.com/o/oauth2/auth",
"token_uri": "https://oauth2.googleapis.com/token",
"auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
"client_x509_cert_url": ""
};
return ContentService.createTextOutput(JSON.stringify(json)).setMimeType(ContentService.MimeType.JSON);
}
GASで上記ファイルを作成後、ウェブアプリケーションとして導入
を行います。
その時に発行されるURLを下記コードに入れることで認証なしで実行可能となります。
※アクセス範囲は全員(匿名ユーザを含む)
にしてください。
スプレッドシート操作をする方法
事前に操作すスプレッドシートに上記JSONファイルで出てきた中の
client_emailのアドレスを共有する必要があるので注意ください。
import requests
import gspread
import json
from oauth2client.service_account import ServiceAccountCredentials
scope = ['https://spreadsheets.google.com/feeds','https://www.googleapis.com/auth/drive']
# 上記で発行されたURLを記載
json_file = 'url'
# URLの情報を辞書型へ変換
key = json.loads(requests.get(json_file).text)
# 通常「ServiceAccountCredentials.from_json_keyfile_name」でJSONファイルのディレクトリを指定するが
# 辞書型データを直接読み込ませる
credentials = ServiceAccountCredentials.from_json_keyfile_dict(key, scope)
gc = gspread.authorize(credentials)
ss_id = 'スプレッドシートのID'
sht_name = 'シート名'
workbook = gc.open_by_key(ss_id)
worksheet = workbook.worksheet(sht_name)
ただし、APIを叩ける頻度は100秒間で100回が上限なので、注意ください。
https://console.cloud.google.com/apis/api/sheets.googleapis.com/quotas?hl=ja
ドライブ操作をする方法
ドライブ操作するための準備
スプレッドシート同様操作するフォルダに権限を与えるのを忘れずに行ってください。
import json
import requests
from pydrive.auth import GoogleAuth
from pydrive.drive import GoogleDrive
from oauth2client.service_account import ServiceAccountCredentials
scope = ['https://www.googleapis.com/auth/drive']
# 上記で発行されたURLを記載
json_file = 'url'
# URLの情報を辞書型へ変換
key = json.loads(requests.get(json_file).text)
# 通常「ServiceAccountCredentials.from_json_keyfile_name」でJSONファイルのディレクトリを指定するが辞書を直接読み込ませる
credentials = ServiceAccountCredentials.from_json_keyfile_dict(key, scope)
gauth = GoogleAuth()
gauth.credentials = credentials
drive = GoogleDrive(gauth)
ファイルのアップデート
#IDを指定してUPLOADする
FOLDER_ID = ''
f = drive.CreateFile({'title' : 'ファイル名.txt',
'parents' : [{'id' : FOLDER_ID }]})
f.SetContentString("Hello World !")
f.Upload()
ドライブからフォルダIDやファイルIDを検索する方法
def get_folderid(FORDER_NAME):
"""
フォルダ名からフォルダIDを取得する関数
"""
FORDER_ID = ''
for folder_list in drive.ListFile({'q':"mimeType='application/vnd.google-apps.folder'"}):
FORDER_ID = [folder['id'] for folder in folder_list if folder['title'] == FORDER_NAME][0]
return FORDER_ID
if FORDER_ID:
break
def get_fileid(FORDER_ID, FILE_NAME):
"""
フォルダIDとファイル名からファイルIDを取得する関数
"""
for file_list in drive.ListFile({'q': f"'{FORDER_ID}' in parents"}):
FILE_ID = ''
FILE_ID = [file['id'] for file in file_list if file['title'] == FILE_NAME][0]
return FILE_ID
if FILE_ID:
break
csvデータをpandasで扱う方法
import pandas as pd
file_id = 'ファイルID'
file_name = 'ファイル名.csv'
f = drive.CreateFile({'id': file_id})
f.GetContentFile(file_name)
df = pd.read_csv(file_name, encoding='CP932', header=None)
df.head()
import pandas as pd
from io import StringIO
file_id = 'ファイルID'
downloaded = drive.CreateFile({'id': file_id})
csv = StringIO(downloaded.GetContentString())
df = pd.read_csv(csv)
df.head()