Python - Gspread 请求错误 401

Python - Gspread Request Error 401

我目前正在制作一个连接到 Google-电子表格 (gspread) 的 Discord-bot。 但是在我使用 运行 一段时间后,它开始发出错误并且无法再连接到我的 gspread(除非我重新启动它)。

我收到的错误:(https://hastebin.com/odutucawuv.tex)

Ignoring exception in command sub
Traceback (most recent call last):
File "C:\Python36\lib\site-packages\discord.py-0.16.10-
py3.6.egg\discord\ext\commands\core.py", line 50, in wrapped
ret = yield from coro(*args, **kwargs)
File "C:\Users\simvid-5\Desktop\Pogomoves\DiscordBot.py", line 65, in sub
val = worksheet.cell(cell_name.row, cell_name.col+4)
File "C:\Python36\lib\site-packages\gspread-0.6.2-
py3.6.egg\gspread\models.py", line 392, in cell
self._cell_addr(row, col))
File "C:\Python36\lib\site-packages\gspread-0.6.2-
py3.6.egg\gspread\client.py", line 210, in get_cells_cell_id_feed
r = self.session.get(url)
File "C:\Python36\lib\site-packages\gspread-0.6.2-
py3.6.egg\gspread\httpsession.py", line 73, in get
return self.request('GET', url, params=params, **kwargs)
File "C:\Python36\lib\site-packages\gspread-0.6.2-
py3.6.egg\gspread\httpsession.py", line 69, in request
response.status_code, response.content))
gspread.exceptions.RequestError: (401, '401: 
b\'<HTML>\n<HEAD>\n<TITLE>Unauthorized</TITLE>\n</HEAD>\n<BODY 
BGCOLOR="#FFFFFF" TEXT="#000000">\n<H1>Unauthorized</H1>\n<H2>Error 
401</H2>\n</BODY>\n</HTML>\n\'')

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
File "C:\Python36\lib\site-packages\discord.py-0.16.10-
py3.6.egg\discord\ext\commands\bot.py", line 846, in process_commands
yield from command.invoke(ctx)
File "C:\Python36\lib\site-packages\discord.py-0.16.10-
py3.6.egg\discord\ext\commands\core.py", line 374, in invoke
yield from injected(*ctx.args, **ctx.kwargs)
File "C:\Python36\lib\site-packages\discord.py-0.16.10-
py3.6.egg\discord\ext\commands\core.py", line 54, in wrapped
raise CommandInvokeError(e) from e
discord.ext.commands.errors.CommandInvokeError: Command raised an exception: 
RequestError: (401, '401: 
b\'<HTML>\n<HEAD>\n<TITLE>Unauthorized</TITLE>\n</HEAD>\n<BODY 
BGCOLOR="#FFFFFF" TEXT="#000000">\n<H1>Unauthorized</H1>\n<H2>Error 
401</H2>\n</BODY>\n</HTML>\n\'')
Ignoring exception in command add
Traceback (most recent call last):
File "C:\Users\simvid-5\Desktop\Pogomoves\DiscordBot.py", line 130, in add
cell_name = worksheet.find(str(member))
File "C:\Python36\lib\site-packages\gspread-0.6.2-
py3.6.egg\gspread\models.py", line 711, in find
return self._finder(finditem, query)
File "C:\Python36\lib\site-packages\gspread-0.6.2-
py3.6.egg\gspread\models.py", line 696, in _finder
cells = self._fetch_cells()
File "C:\Python36\lib\site-packages\gspread-0.6.2-
py3.6.egg\gspread\models.py", line 331, in _fetch_cells
feed = self.client.get_cells_feed(self)
File "C:\Python36\lib\site-packages\gspread-0.6.2-
py3.6.egg\gspread\client.py", line 176, in get_cells_feed
r = self.session.get(url)
File "C:\Python36\lib\site-packages\gspread-0.6.2-
py3.6.egg\gspread\httpsession.py", line 73, in get
return self.request('GET', url, params=params, **kwargs)
File "C:\Python36\lib\site-packages\gspread-0.6.2-
py3.6.egg\gspread\httpsession.py", line 69, in request
response.status_code, response.content))
gspread.exceptions.RequestError: (401, '401: 
b\'<HTML>\n<HEAD>\n<TITLE>Unauthorized</TITLE>\n</HEAD>\n<BODY 
BGCOLOR="#FFFFFF" TEXT="#000000">\n<H1>Unauthorized</H1>\n<H2>Error 
401</H2>\n</BODY>\n</HTML>\n\'')

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
File "C:\Python36\lib\site-packages\discord.py-0.16.10-
py3.6.egg\discord\ext\commands\core.py", line 50, in wrapped
ret = yield from coro(*args, **kwargs)
File "C:\Users\simvid-5\Desktop\Pogomoves\DiscordBot.py", line 136, in add
cell_list = worksheet.range('A2:A100')
File "C:\Python36\lib\site-packages\gspread-0.6.2-
py3.6.egg\gspread\models.py", line 72, in wrapper
return method(self, *args, **kwargs)
File "C:\Python36\lib\site-packages\gspread-0.6.2-
py3.6.egg\gspread\models.py", line 412, in range
params={'range': name, 'return-empty': 'true'}
File "C:\Python36\lib\site-packages\gspread-0.6.2-
py3.6.egg\gspread\client.py", line 176, in get_cells_feed
r = self.session.get(url)
File "C:\Python36\lib\site-packages\gspread-0.6.2-
py3.6.egg\gspread\httpsession.py", line 73, in get
return self.request('GET', url, params=params, **kwargs)
File "C:\Python36\lib\site-packages\gspread-0.6.2-
py3.6.egg\gspread\httpsession.py", line 69, in request
response.status_code, response.content))
gspread.exceptions.RequestError: (401, '401: 
b\'<HTML>\n<HEAD>\n<TITLE>Unauthorized</TITLE>\n</HEAD>\n<BODY 
BGCOLOR="#FFFFFF" TEXT="#000000">\n<H1>Unauthorized</H1>\n<H2>Error 
401</H2>\n</BODY>\n</HTML>\n\'')

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
File "C:\Python36\lib\site-packages\discord.py-0.16.10-
py3.6.egg\discord\ext\commands\bot.py", line 846, in process_commands
yield from command.invoke(ctx)
File "C:\Python36\lib\site-packages\discord.py-0.16.10-
py3.6.egg\discord\ext\commands\core.py", line 374, in invoke
yield from injected(*ctx.args, **ctx.kwargs)
File "C:\Python36\lib\site-packages\discord.py-0.16.10-
py3.6.egg\discord\ext\commands\core.py", line 54, in wrapped
raise CommandInvokeError(e) from e
discord.ext.commands.errors.CommandInvokeError: Command raised an exception: 
RequestError: (401, '401: 
b\'<HTML>\n<HEAD>\n<TITLE>Unauthorized</TITLE>\n</HEAD>\n<BODY 
BGCOLOR="#FFFFFF" TEXT="#000000">\n<H1>Unauthorized</H1>\n<H2>Error 
401</H2>\n</BODY>\n</HTML>\n\'')

我正在使用的功能之一,如果它有助于理解上述问题,如果有必要修复它,我可以提供更多我的代码:

import discord
import asyncio
import random
import pickle
import os
import gspread
import time

from oauth2client.service_account import ServiceAccountCredentials
from discord.ext import commands

prefix = '!'

def returnPrefix():
    global prefix
    return prefix

bot = commands.Bot(returnPrefix())

scope = ['https://spreadsheets.google.com/feeds']
credentials = 
ServiceAccountCredentials.from_json_keyfile_name('GoogleSpreadsheetCreds.json', scope)
gc = gspread.authorize(credentials)
sh = gc.open("MyWorksheet")
worksheet = sh.sheet1


@bot.event
async def on_ready():
        print('Logged in as')
        print(bot.user.name)
        print(bot.user.id)
        print('-----')
        await bot.change_presence(game=discord.Game(name='Whosebug'))



@bot.command(pass_context=True)
@commands.has_role("Premium")
async def sub(ctx, member: discord.Member = None):
    global cell_name
    if member is None:
        member = ctx.message.author

    #Delete user_command.
    await bot.delete_message(ctx.message)

    #Retrieve user from commander.
    Username = '{0}'.format(member)

    try:
        #Try to find the username in spreadsheet.
        cell_name = worksheet.find(Username)
    except: #If we dont find the username.
        await bot.say("Your name ("+Username+") was not found, please contact someone for help.")

    if cell_name.value == Username: #If we find the username.
        #Retrieve some values.
        val = worksheet.cell(cell_name.row, cell_name.col+4)
        val_date = worksheet.cell(cell_name.row, cell_name.col+3)
        remaining_days = val.value
        remaining_date = val_date.value

        #Send a message to a member.
        await bot.send_message(member,
                            "```Username: "+ Username+
                            "\nRemaining days: "+remaining_days+
                            "\nDate for expiration: "+remaining_date+"```")

这里唯一可能的罪魁祸首是您的帐户凭据。尝试在您的 Google 开发者控制台上创建新凭据并使用它。

您的访问令牌将在一段时间后过期。来自 OAuth 2.0 docs:

  1. Refresh the access token, if necessary.

Access tokens have limited lifetimes. If your application needs access to a Google API beyond the lifetime of a single access token, it can obtain a refresh token. A refresh token allows your application to obtain new access tokens.

Note: Save refresh tokens in secure long-term storage and continue to use them as long as they remain valid. Limits apply to the number of refresh tokens that are issued per client-user combination, and per user across all clients, and these limits are different. If your application requests enough refresh tokens to go over one of the limits, older refresh tokens stop working.

我不相信 gspread 有能力处理刷新令牌。您可能只能捕获此异常并根据需要重新进行身份验证。

编辑:

查看 gspread 来源后,我认为您 可能 可以通过简单地调用 gc.login()

来刷新您的令牌

编辑:

这个issue was filed with gspread a couple of years ago but it was closed for no apparent reason. Here is one approach来解决它:

def add_row(row):
    try:
        gs_client = gspread.authorize(creds)
        gs_worksheet = gs_client.open("foo").sheet1
        if creds.access_token_expired:
            gs_client.login()  # refreshes the token
        gs_worksheet.append_row(row)
    except Exception, e:
        traceback.print_exc()

但我认为这太过分了。您应该可以在 try: 块之前调用 gc.login()

gc.login()
try:
    #Try to find the username in spreadsheet.
    cell_name = worksheet.find(Username)
except: #If we dont find the username.