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