raspberry pi python gspread OAuth 2 错误

raspberry pi python gspread OAuth 2 error

我有一个脚本,它应该每 2 分钟在 google 电子表格中追加一行。 当我启动脚本时,它运行良好,但一段时间后出现以下错误:

{
  "error": {
    "code": 401,
    "message": "Request had invalid authentication credentials. Expected OAuth 2 access token, login cookie or other valid authentication credential. See https://developers.google.com/identity/sign-in/web/devconsole-project.",
    "status": "UNAUTHENTICATED"
  }
}

Python 脚本

import gspread
from oauth2client.service_account import ServiceAccountCredentials
scope = ['https://spreadsheets.google.com/feeds', 'https://www.googleapis.com/auth/drive']

credentials = ServiceAccountCredentials.from_json_keyfile_name('auth.json', scope)
gc = gspread.authorize(credentials)

wks = gc.open('sheet').sheet1

while True:
    #here is some other code and 2 minutes delay
    wks.append_row(["test", "test2"])

Auth.json

{
  "type": "x",
  "project_id": "x",
  "private_key_id": "x",
  "private_key": "x",
  "client_email": "x",
  "client_id": "x",
  "auth_uri": "https://accounts.google.com/o/oauth2/auth",
  "token_uri": "https://accounts.google.com/o/oauth2/token",
  "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
  "client_x509_cert_url": "x"
}

Google发行的代币是短期代币,很快就会过期。 ServiceAccountCredentials 有一个 refresh 方法来获取新令牌。在您的情况下,由于它每 2 分钟调用一次,因此您可以每 2 分钟调用一次 gc.login()

while True:
    gc.login()

我不确定为什么它不自行刷新(应该)。仅供参考,oauth2client 已弃用,请考虑使用其他东西。以下是有关如何将其与 Authlib 一起使用的提示:https://blog.authlib.org/2018/authlib-for-gspread

授权令牌超时与我的经验不一致——有时正好是一个小时,但其他时候可能要长得多(比如几个小时)或少得多。

我有一个项目通过服务帐户每分钟向 Google 表格发送数据。当我第一次启动它时,我的脚本与 KT Work 的脚本一样 运行ged,初始登录授权在主循环之外。不用说,我和其他人一样开始 运行 遇到 401 UNAUTHORIZED 故障。

所以我在主循环中添加了一个额外的 gc.login(),每 45 分钟触发一次计数器。我仍然 运行 遇到 401 UNAUTHORIZED 失败,所以我将它减少到 30 分钟,然后是 20 分钟,然后甚至只有 10 分钟,但我仍然会每天至少看到一次相同的错误,有时甚至更多。

我终于摆脱了计数器,并开始在循环的每次迭代中(即每分钟)执行 gc.login() 。虽然这通常似乎可以解决 401 UNAUTHORIZED 错误,但它并不是万灵药!为什么?因为现在我偶尔会看到 503 UNAVAILABLE 错误,这与停止脚本的效果相同。

那么最终的解决方案是什么?添加一个执行主脚本的简单看门狗脚本,如果失败则重新启动它。我试过几个例子,但我在几个月前 运行 找到了一个简单、优雅的例子:

[https://www.alexkras.com/how-to-restart-python-script-after-exception-and-run-it-forever/]

所以我定制了自己的 "RunScriptForeverWatchdog.py" 脚本如下:

#!/usr/bin/python
from subprocess import Popen
import sys

filename = sys.argv[1]
while True:
    print("\n(Re-)Starting script:  " + filename)
    p = Popen("python " + filename, shell=True)
    p.wait()

现在我只是以主脚本为参数执行这个看门狗脚本,每次主脚本失败时,它会立即由​​前者重新生成。