谷歌日历API:错误代码403:请求缺少有效的API密钥。

3

最近我开始研究Google日历 API,希望为自己制作一个个人应用程序,可以随机生成每天的重点内容,并将其转换为事件后传递给我的 Google 日历。我在这方面几乎没有任何经验,但是谷歌的快速入门指南帮助我了解了一些基本知识。我主要使用了他们提供的 Python 快速入门代码,并添加了一些自己的函数来创建和删除事件,然后调整了范围以包括创建和删除事件所需的权限。

我使用的代码:

from __future__ import print_function

import datetime
from hashlib import new
import os.path
from re import S

from google.auth.transport.requests import Request
from google.oauth2.credentials import Credentials
from google_auth_oauthlib.flow import InstalledAppFlow
from googleapiclient.discovery import build
from googleapiclient.errors import HttpError

from highlightsGenerator import *

# If modifying these scopes, delete the file token.json.
SCOPES = ['https://www.googleapis.com/auth/calendar.readonly',
          'https://www.googleapis.com/auth/calendar.events',
          'https://www.googleapis.com/auth/calendar']

templateEvent = {
                'summary': 'Daily Highlight',
                'description': '',
                'start': {
                    'dateTime': '',
                    },
                'end': {
                    'dateTime': '',
                    },
                'reminders': {
                    'useDefault': True,
                    },
            }

def createHighlightEvents(service):
    workingDate = datetime.date.today()
    workingDate += datetime.timedelta(days=1)
    highlightSchedule = scheduleGenerator()
    print(highlightSchedule)
    for k in highlightSchedule:
        newEvent = templateEvent
        newEvent['description'] = k
        newEvent['start']['dateTime'] = str(workingDate) + 'T13:00:00+3:00'
        newEvent['end']['dateTime'] = str(workingDate) + 'T17:00:00+03:00'
        service.events().insert(calendarId='primary', body=newEvent).execute()
        workingDate += datetime.timedelta(days=1)

def deleteHighlightEvents(service):
    now = datetime.datetime.utcnow().isoformat() + 'Z'  # 'Z' indicates UTC time
    events_result = service.events().list(calendarId='primary', q='Daily Highlight',timeMin=now,
                                        maxResults=20, singleEvents=True,
                                        orderBy='startTime').execute()
    events = events_result.get('items', [])

    # if not events:
    #         print('No upcoming events found.')
    #         return

    for event in events:
        eID = event['id']
        service.events().delete(calendarId='primary', eventId=eID).execute()

def reRollHighlightEvents(service):
    deleteHighlightEvents(service)
    createHighlightEvents(service)

def getDate(dateTime):
    dateStr = dateTime[:len(dateTime) - 6]
    date = datetime.datetime.strptime(dateStr, '%Y-%m-%dT%H:%M:%S')
    return date

def shiftHighlights(service, numDays):
    now = datetime.datetime.utcnow().isoformat() + 'Z'  # 'Z' indicates UTC time
    events_result = service.events().list(calendarId='primary', q='Daily Highlight',timeMin=now,
                                        maxResults=20, singleEvents=True,
                                        orderBy='startTime').execute()
    events = events_result.get('items', [])

    if not events:
            print('No upcoming events found.')
            return
    
    for event in events:
        newStartDate = getDate(event['start']['dateTime']) + datetime.timedelta(days=numDays)
        newEndDate = getDate(event['end']['dateTime']) + datetime.timedelta(days=numDays)
        newStartDateStr = 'T'.join([str(newStartDate.date()), str(newStartDate.time())])
        newEndDateStr = 'T'.join([str(newEndDate.date()), str(newEndDate.time())])
        newEvent = event
        newEvent['start']['dateTime'] = newStartDateStr + '+03:00'
        newEvent['end']['dateTime'] = newEndDateStr + '+03:00'

        service.events().update(calendarId='primary', eventId=event['id'], body=newEvent).execute()
        


def main():
    """Shows basic usage of the Google Calendar API.
    Prints the start and name of the next 10 events on the user's calendar.
    """
    creds = None
    # The file token.json stores the user's access and refresh tokens, and is
    # created automatically when the authorization flow completes for the first
    # time.
    if os.path.exists('token.json'):
        creds = Credentials.from_authorized_user_file('token.json', SCOPES)
   # If there are no (valid) credentials available, let the user log in.
    if not creds or not creds.valid:
        if creds and creds.expired and creds.refresh_token:
            creds.refresh(Request())
        else:
            flow = InstalledAppFlow.from_client_secrets_file(
                'client_secret_158794507060-ucqbqgapmlf7lmvre6knjc5nehd00ms0.apps.googleusercontent.com.json', SCOPES)
            creds = flow.run_local_server(port=0)
        # Save the credentials for the next run
        with open('token.json', 'w') as token:
            token.write(creds.to_json())

    try:
        service = build('calendar', 'v3', credentials=creds)

        # Call the Calendar API
        now = datetime.datetime.utcnow().isoformat() + 'Z'  # 'Z' indicates UTC time
        print('Getting the upcoming 10 events')
        events_result = service.events().list(calendarId='primary', timeMin=now,
                                              maxResults=10, singleEvents=True,
                                              orderBy='startTime').execute()
        events = events_result.get('items', [])

        if not events:
            print('No upcoming events found.')
            return

        # Prints the start and name of the next 10 events
        for event in events:
            start = event['start'].get('dateTime', event['start'].get('date'))
            print(start, event['summary'])

        userInput = input('Create (c), Delete (d), Re-Roll (r), Shift (s) highlights?\n')
        if userInput == 'c':
            createHighlightEvents(service)
        elif userInput == 'd':
            deleteHighlightEvents(service)
        elif userInput == 'r':
            reRollHighlightEvents(service)
        elif userInput == 's':
            numDays = input('How many days would you like to shift by?  (x) to cancel\n')
            if numDays != 'x' and numDays.isnumeric:
                shiftHighlights(service, int(numDays))
            elif numDays != 'x':
                print('Please input a number or (x) to cancel')
        else:
            print('That is not one of the options')

    except HttpError as error:
        print('An error occurred: %s' % error)


if __name__ == '__main__':
    main()

我设法让它做我想要的事情,一度效果良好,但昨天尝试运行时却因为无效请求而出现了http 400错误。 点击提供的链接后,我看到了这个:

{
  "error": {
    "code": 403,
    "message": "The request is missing a valid API key.",
    "errors": [
      {
        "message": "The request is missing a valid API key.",
        "domain": "global",
        "reason": "forbidden"
      }
    ],
    "status": "PERMISSION_DENIED"
  }
}

现在,您可能已经看到了我留下的代码,用于检索和显示前10个即将到来的事件。它仍然能够正常运行,但是如果尝试创建或删除事件,则会出现此错误消息。我对这条消息感到非常困惑,因为我相信我已经完成了所有必要的授权。我的客户端密钥没有更改,但即使如此,我也重新下载了它,以查看是否有任何变化,但没有。我删除了令牌并运行了授权,再次允许授权。这也没有带来任何成果,据我所知,我的范围是正确的。
在这里有一些类似错误的问题,但是它们似乎由于不同的原因而出现(从我能看出来),或者是因为他们缺少一个我认为我已经拥有的授权。
再次说明,我几乎没有这方面的经验,因此可能有一些非常明显的事情我没有做,但是我恐怕不知道那是什么。
如有任何帮助,将不胜感激。

我不确定,但如果您可以检索和显示,但无法创建和删除,则可能是因为您的API密钥没有所有必要的权限。 Google API往往提供非常细粒度的权限,以便您可以将授权限制在您需要的功能上。 - Luke Nelson
3个回答

2

这可能对其他人没有帮助,但对我来说是解决方案。这也许就是@Oriol Castander想要表达的意思。我一直收到403错误,说缺少API密钥。但对我来说,这是一个虚假的错误。实际问题是我在events().list命令中使用的日期。我使用了一个精确的日期(2022年6月4日),而不是now(),我需要按照以下格式进行格式化:

date=datetime.datetime(2022, 6, 4,0,0,0,0).isoformat() + 'Z'

一旦我正确格式化了日期,调用就能正常运行。


2
我已经重新创建并运行了您的代码,但我没有遇到 403 错误。代码看起来很好,应该可以工作,特别是因为您可以通过列表命令检索数据。这不是一个明确的答案,但为了使其工作,您可以尝试以下操作:
  • 在禁用和启用日历 API 后,重新下载 credentials.json 文件。
  • 只使用 'https://www.googleapis.com/auth/calendar' 范围,因为它是最不限制的范围,并且是创建事件所需的。
  • 删除 token.json 文件以强制 OAuth 重新登录。

然而,当您将其运行时,我确实发现了一个错误,这将导致您的代码失败。 'start''end' 属性都需要一个 'dateTime' 和一个 'timeZone' 属性,就像此示例中所做的那样。 因此,这段代码将无法运行:

newEvent['start']['dateTime'] = str(workingDate) + 'T13:00:00+3:00'
newEvent['end']['dateTime'] = str(workingDate) + 'T17:00:00+03:00'

应该使用这个替代


newEvent['start']['dateTime'] = str(workingDate) + 'T13:00:00'
newEvent['start']['timeZone'] = 'Your timeZone'
newEvent['end']['dateTime'] = str(workingDate) + 'T17:00:00'#Having the +3:00 will fail
newEvent['end']['timeZone'] = 'Your timeZone'

你可以在维基百科上找到你所在的时区,当然啦:https://en.wikipedia.org/wiki/List_of_tz_database_time_zones

0

实际上我的代码也出现了同样的错误,我已经更改了datetime的代码,但仍然出现相同的错误。我该怎么做才能解决这个问题呢?以下是我的代码 -> def create_events(self): start_date = datetime.datetime(2023,1,5,18,30,0,0).isoformat()+'Z' end_date = datetime.datetime(2023,1,5,18,45,0,0).isoformat()+'Z'

    calendar_Id = 'c_bcvf5uaav97iq563i3msuetl1k@group.calendar.google.com'
    hours_adjustment = -8
    events_request_body = {
        'start':{
            'dateTime':start_date,
            'timeZone':'Asia/kolkata'
        },
        'end':{
            'dateTime':end_date,
            'timeZone': 'Asia/kolkata'
        },
    }
    calendar = service.events().insert(calendarId=calendar_Id,
                                       body=events_request_body,).execute()
    return calendar

我该如何在三天内解决错误并处理它...我非常沮丧。


1
目前你的回答不够清晰,请编辑并添加更多细节,以帮助其他人理解它如何回答问题。你可以在帮助中心找到有关如何编写好答案的更多信息。 - Community

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接