質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.35%
Google スプレッドシート

Google スプレッドシートは、フリーで利用できる表計算ソフト。Webアプリのためインターネットに接続することで利用できます。チャートやグラフの作成のほか、シートを他のユーザーと共有したり、同時に作業を進めることも可能です。

Google Apps Script

Google Apps ScriptはGoogleの製品と第三者のサービスでタスクを自動化するためのJavaScriptのクラウドのスクリプト言語です。

例外

例外(exception)とは、プログラムの処理実行中に発生する、通常の処理の続行を妨げる特殊な事象のことを呼びます。この「例外」が発生した場合に、現在の処理を中断し、変わりに別の処理を実行させる事を「例外処理」と呼びます。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

Q&A

解決済

2回答

1845閲覧

pythonでclass無いの全ての関数が経由する関数を作成したい

Yuiti628

総合スコア71

Google スプレッドシート

Google スプレッドシートは、フリーで利用できる表計算ソフト。Webアプリのためインターネットに接続することで利用できます。チャートやグラフの作成のほか、シートを他のユーザーと共有したり、同時に作業を進めることも可能です。

Google Apps Script

Google Apps ScriptはGoogleの製品と第三者のサービスでタスクを自動化するためのJavaScriptのクラウドのスクリプト言語です。

例外

例外(exception)とは、プログラムの処理実行中に発生する、通常の処理の続行を妨げる特殊な事象のことを呼びます。この「例外」が発生した場合に、現在の処理を中断し、変わりに別の処理を実行させる事を「例外処理」と呼びます。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

0グッド

2クリップ

投稿2020/11/05 22:50

編集2020/11/06 01:49

# 前提
###開発言語
・python3
###使用
・自動ツールで、処理のパラメータなどをスプレッドシートから読み取り、結果をスプレッドシートに記入しています。
・ツールは複数実行される
・ツール数は20以上で、同時には実行されないように時間をずらしていますが、どうしても複数重なるタイミングがあります。その時にエラーが発生

困っていること

pythonのコードの書き方で、例外処理をどうすれば綺麗に書けるかわかりません。
pythonのgspreadを使っていてアクセス制限が生じます。
それは、100秒間に100アクセスしかできない制約で、このエラー自体は起きるものだと想定しています。
そのエラーの場合100秒間待機してから再呼び出しをしたいと考えています。

現状

python

1 2class Spread_Sheet: 3 def __init__(self): 4 # シートのオブジェクトを作成 5 #2つのAPIを記述しないとリフレッシュトークンを3600秒毎に発行し続けなければならない 6 scope = ['https://spreadsheets.google.com/feeds','https://www.googleapis.com/auth/drive'] 7 #認証情報設定 8 json_string = gas_json.json_string 9 credentials = ServiceAccountCredentials._from_parsed_json_keyfile(json_string, scope) 10 #OAuth2の資格情報を使用してGoogle APIにログインします。 11 gc = gspread.authorize(credentials) 12 13 self.workbook = gc.open_by_key(SPREADSHEET_KEYS) 14 15 16 # シートが存在するのかチェック 17 def exists_vsheet_check(self,s_name): 18 is_Exists = False 19 worksheets = self.workbook.worksheets() # シート一覧を取得 20 worksheets_list = [ss.title for ss in worksheets] 21 22 if s_name in worksheets_list: 23 is_Exists = True 24 return is_Exists 25 26 # パラメータの取得 27 def get_parameter(self,s_name): 28 pass 29 30 # データの更新 31 def set_date(self,s_name): 32 pass 33 34 # ・ 35 # ・ 36 # ・ 37

この様に、スプレッドシートを操作するクラスを用意して、全てのアクセスをそのクラスからするようにしています。
基本的にself.workbookを使うと1回のカウントとなり、100秒間に100回を超えるとエラーがでます。

そのエラーがgspread.exceptions.APIErrorです。これに例外処理したら次はrequests.exceptions.connectionerrorのエラーが出たので下記のように変更しました。

python

1 2class Spread_Sheet: 3 e_count = 0 4 while True: 5 try: 6 7 # シートのオブジェクトを作成 8 #2つのAPIを記述しないとリフレッシュトークンを3600秒毎に発行し続けなければならない 9 scope = ['https://spreadsheets.google.com/feeds','https://www.googleapis.com/auth/drive'] 10 #認証情報設定 11 json_string = gas_json.json_string 12 credentials = ServiceAccountCredentials._from_parsed_json_keyfile(json_string, scope) 13 #OAuth2の資格情報を使用してGoogle APIにログインします。 14 gc = gspread.authorize(credentials) 15 #共有設定したスプレッドシートキーを変数[SPREADSHEET_KEY]に格納する。 16 SPREADSHEET_KEYS = ff.get_post_spread_key() 17 18 # ワークブック main 19 self.workbook = gc.open_by_key(SPREADSHEET_KEYS[0]) 20 # ワークブック 動画のあるシート 21 self.workbook_video = gc.open_by_key(SPREADSHEET_KEYS[(ff.get_tool()-1)//10]) 22 return 23 except: 24 random.randint(100,150) 25 e_count +=1 26 if e_count > 5: 27 raise 'Set_ALL_mail_message' 28 29 30 # シートが存在するのかチェック 31 def exists_vsheet_check(self,s_name): 32 e_count = 0 33 while True: 34 try: 35 36 is_Exists = False 37 worksheets = self.workbook_video.worksheets() # シート一覧を取得 38 worksheets_list = [ss.title for ss in worksheets] 39 40 if s_name in worksheets_list: 41 is_Exists = True 42 return is_Exists 43 44 except: 45 random.randint(100,150) 46 e_count +=1 47 if e_count > 5: 48 raise 'exists_vsheet_check' 49 50

全てのアクセスするとき、エラーが出たら5回は繰り返しています 笑
絶対間違っていると思ってここをなんとかしたいです。

考えたこと

要は、例外処理する場所を一か所にしたいです。
なので、高級関数を使って全部関数が経由する関数を作れば良いのでは無いかと思いましたが、引数がまちまちだったので向いていないと判断しました。

classにそういう機能が無いかな?と思ったのですが見つけることができませんでした。
何か良い方法はないでしょうか?

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

ベストアンサー


※本来は、たとえ面倒でも、関数ごとに例外処理を行うのが正攻法だと個人的には考えます。
(ちょっと楽にしたいならデコレータを用いましょう)
なぜならば、関数(処理の単位)ごとにキャッチすべき例外や対処内容は異なることが普通だと思うからです。
また、サーバへの負荷を軽減するためのタイムアウト措置をかような方法で回避することは、本来の趣旨から外れるのでは、という考え方もできます
(タイムアウト措置が実装されている意味は、「タイムアウトが頻発するほどの速度で連続処理を行うべきではない」というイデオロギーが根底にあるかもしれないのです)


閑話休題。

「例外処理する場所を一か所にしたい」とは、かみ砕くと、gspreadを操作するとき回数制限で発生する例外処理を関数毎に書きたくない、ことだと理解しました。

この目的を達するために、やや強引ですが、gspreadのソースを参考に、すべてのAPIリクエストの元締めであるgspreadライブラリのclientオブジェクトのrequest関数を書き換えてみました

下記はクラスを使わず平文でシート操作する場合となっています。
質問者さんの元のSpreadSheetクラスへの組み込みとかは御自分で考えてみてください。
(元のコードはgas_jsonとかよくわからなかったので)

また、下記はシングルスレッドで各処理を行っているという前提です。

import gspread from gspread.exceptions import APIError import time # 認証部分は省略 # gspread.Client.request()関数を上書きするカスタム関数 def custom_request(self, method, endpoint, params=None, data=None, json=None, files=None, headers=None, ): for _ in range(5): response = getattr(self.session, method)( endpoint, json=json, params=params, data=data, files=files, headers=headers, ) if response.ok: return response if response.status_code == 429: # リクエスト制限が発生したときは100+1秒待つ print("request limit. wait 100 secs") time.sleep(101) else: # その他のエラーの場合は5秒待ってリトライ print(f"Unknown Error:{response.status_code}") time.sleep(5) continue # リクエスト制限以外で5回連続でエラーが起きた場合は本当に例外を発生させる。 else: raise APIError(response) # 関数を書き換える。 gspread.Client.request = custom_request # 以下は動作確認用のコード-------------- for i in range(1,200): print(i) val = int(worksheet.cell(i,1).value) output_val = val + 100 worksheet.update_cell(i+1,1, ouput_val)

出力結果

1 2 (略) 112 113 114 115 request limit. wait 100 secs <==ここでリクエスト制限がかかり約101秒待つ 116               <==100秒以上待ったのでリクエスト制限が解除されて動作再開 117 (略)

投稿2020/11/06 13:23

編集2020/11/06 13:42
sfdust

総合スコア1137

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Yuiti628

2020/11/06 13:38

これは本当にすごいです! ありがとうございます???? gspreadの方をいじるなんて考えもしなかったです。 そんな方法があるなんて。
guest

0

・自動ツールで、処理のパラメータなどをスプレッドシートから読み取り、結果をスプレッドシートに記入しています。

の内容が書いてないので推測になりますが、新規シートの追加が頻繁に行なわれるのでなければ、exists_vsheet_checkで毎回シートタイトルのリストworksheets_listを生成するのではなく、__init___であらかじめ作成しておき、exists_vsheet_checkではそれを参照するだけにすれば、self.workbookへのアクセス数を抑えることができるのでは。

途中で新規シートが追加されるのであれば、その後でworksheets_listを更新するメソッド(を追加作成しておいて)を呼べばいいのです。

投稿2020/11/06 01:36

Daregada

総合スコア11990

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Yuiti628

2020/11/06 01:47

説明不足で申し訳ありません。 中の結構色々あります。データ取得からセットまで。 また、ツール数も多いので、どうしてもアクセス制限にはなると思っています。 そのため、例外の書き方についての質問でした。 省略しすぎて申し訳ありません。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.35%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問