I use this code to test google calendar api,when I use calendarId='primary', there is no error.
But when I use calendarId='uf0udovlhgel0u7a1ifs69o2u8#group.calendar.google.com'.
The error message in my pycharm console is:
gleapiclient.errors.HttpError: https://www.googleapis.com/calendar/v3/calendars/uf0udovlhgel0u7a1ifs69o2u8%40group.calendar.google.com/events?maxResults=10&singleEvents=true&orderBy=startTime&alt=json returned "Insufficient Permission">
In fact,I have this Calendar ID,you can see it in this picture:
Here is my code:
from __future__ import print_function
import datetime
from googleapiclient.discovery import build
from httplib2 import Http
from oauth2client import file, client, tools
# If modifying these scopes, delete the file token.json.
# SCOPES = 'https://www.googleapis.com/auth/calendar.readonly'
SCOPES = 'https://www.googleapis.com/auth/calendar'
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.
"""
# 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.
store = file.Storage('token.json')
creds = store.get()
if not creds or creds.invalid:
flow = client.flow_from_clientsecrets('./credentials.json', SCOPES)
creds = tools.run_flow(flow, store)
service = build('calendar', 'v3', http=creds.authorize(Http()))
# 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',
# maxResults=10, singleEvents=True,
# orderBy='startTime').execute()
events_result = service.events().list(calendarId='uf0udovlhgel0u7a1ifs69o2u8#group.calendar.google.com',
maxResults=10, singleEvents=True,
orderBy='startTime').execute()
events = events_result.get('items', [])
if not events:
print('No upcoming events found.')
for event in events:
start = event['start'].get('dateTime', event['start'].get('date'))
print(start, event['summary'])
if __name__ == '__main__':
main()
When I click the link in my pycharm console,the error is:
{
"error": {
"errors": [
{
"domain": "usageLimits",
"reason": "dailyLimitExceededUnreg",
"message": "Daily Limit for Unauthenticated Use Exceeded. Continued use requires signup.",
"extendedHelp": "https://code.google.com/apis/console"
}
],
"code": 403,
"message": "Daily Limit for Unauthenticated Use Exceeded. Continued use requires signup."
}
}
How can I fix this error?
I know where is wrong,my python file is in folder A,folder A doesn't have file credentials.json.
So there is error.
This is a very stupid mistake.
Related
So my colleague and I have an application whereby we need to capture the OAuth Redirect from Google's OAuth Server Response, the reason being is we need to send a payload to capture to renew our pickle token, and we need to do it without human intervention. The code looks like this:
#!/usr/bin/env python3
import pickle
import os.path
import pandas as pd
import requests
from googleapiclient.discovery import build
from google_auth_oauthlib.flow import InstalledAppFlow
from google.auth.transport.requests import Request
import base64
from datetime import datetime, timedelta
from urllib.parse import unquote
from bs4 import BeautifulSoup
# If modifying these scopes, delete the file token.pickle.
SCOPES = ['https://www.googleapis.com/auth/gmail.readonly']
def search_message(service, user_id, search_string):
"""
Search the inbox for emails using standard gmail search parameters
and return a list of email IDs for each result
PARAMS:
service: the google api service object already instantiated
user_id: user id for google api service ('me' works here if
already authenticated)
search_string: search operators you can use with Gmail
(see https://support.google.com/mail/answer/7190?hl=en for a list)
RETURNS:
List containing email IDs of search query
"""
try:
# initiate the list for returning
list_ids = []
# get the id of all messages that are in the search string
search_ids = service.users().messages().list(userId=user_id, q=search_string).execute()
# if there were no results, print warning and return empty string
try:
ids = search_ids['messages']
except KeyError:
print("WARNING: the search queried returned 0 results")
print("returning an empty string")
return ""
if len(ids) > 1:
for msg_id in ids:
list_ids.append(msg_id['id'])
return (list_ids)
else:
list_ids.append(ids['id'])
return list_ids
except:
print("An error occured: %s")
def get_message(service, user_id, msg_id):
"""
Search the inbox for specific message by ID and return it back as a
clean string. String may contain Python escape characters for newline
and return line.
PARAMS
service: the google api service object already instantiated
user_id: user id for google api service ('me' works here if
already authenticated)
msg_id: the unique id of the email you need
RETURNS
A string of encoded text containing the message body
"""
try:
final_list = []
message = service.users().messages().get(userId=user_id, id=msg_id).execute() # fetch the message using API
payld = message['payload'] # get payload of the message
report_link = ""
mssg_parts = payld['parts'] # fetching the message parts
part_one = mssg_parts[1] # fetching first element of the part
#part_onee = part_one['parts'][1]
#print(part_one)
part_body = part_one['body'] # fetching body of the message
part_data = part_body['data'] # fetching data from the body
clean_one = part_data.replace("-", "+") # decoding from Base64 to UTF-8
clean_one = clean_one.replace("_", "/") # decoding from Base64 to UTF-8
clean_one = clean_one.replace("amp;", "") # cleaned amp; in links
clean_two = base64.b64decode(clean_one) # decoding from Base64 to UTF-8
soup = BeautifulSoup(clean_two, features="html.parser")
for link in soup.findAll('a'):
if "talentReportRedirect?export" in link.get('href'):
report_link = link.get('href')
break
final_list.append(report_link) # This will create a dictonary item in the final list
except Exception:
print("An error occured: %s")
return final_list
def get_service():
"""
Authenticate the google api client and return the service object
to make further calls
PARAMS
None
RETURNS
service api object from gmail for making calls
"""
creds = None
# The file token.pickle 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.pickle'):
with open('token.pickle', 'rb') as token:
creds = pickle.load(token)
# 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('credentials.json', SCOPES)
creds = flow.run_local_server(port=0)
# Save the credentials for the next run
with open('token.pickle', 'wb') as token:
pickle.dump(creds, token)
auth_link = build('gmail', 'v1', credentials=creds)
parsed_url = unquote(auth_link).split('redirect')[-1]
return parsed_url
def get_report(link_array):
for link in link_array:
df = requests.get(link[0], allow_redirects=True)
# df.encoding
# dt = pd.DataFrame(data=df)
print(link)
# upload_to_database(df) -- Richard Barret please update this function
print(df.text)
## dt.to_csv(r'C:\Users\user\Desktop\api_gmail.csv', sep='\t',header=True)
if __name__ == "__main__":
link_list = []
monday = datetime(2022,12,5)#datetime.now() - timedelta(days=datetime.now().weekday())
thursday = datetime(2022,12,8)#datetime.now() - timedelta(days=datetime.now().weekday() - 3)
query = 'from:messages-noreply#linkedin.com ' + 'after:' + monday.strftime('%Y/%m/%d') + ' before:' + thursday.strftime('%Y/%m/%d')
service = get_service()
mssg_list = search_message(service, user_id='me', search_string=query)
for msg in mssg_list:
link_list.append(get_message(service, user_id='me', msg_id=msg))
get_report(link_list)
It is assumed that you have a directory structure like this:
├── credentials.json
├── gmail_api_linkedin.py
└── requirements.txt
Obviously, you won't have the credentials.json file, but in essence, the code works and redirects us to a login page to retrieve the new pickle:
The main thing is we can't interact with that in an autonomous fashion. As such, how can we capture the URL from the server that prints out the following information the is differenter every single time.
Please visit this URL to authorize this application: https://accounts.google.com/o/oauth2/auth?response_type=code&client_id=212663976989-96o952s9ujadjgfdp6fm0p462p37opml.apps.googleusercontent.com&redirect_uri=http%3A%2F%2Flocalhost%3A58605%2F&scope=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fgmail.readonly&state=ztJir0haFQlvTP79BRthhmEHlSsqIj&access_type=offline
More succinctly, how can we capture the URL in a pythonic manner to send POST and PUT requests to that redirect?
renew our pickle token
I still do not understand why you feel the need to renew your token pickle.
how it all works.
The following example will spawn the consent screen directly on the machine its running on. It then stores the token within the token.json file
token.json
This file contains all the information needed by the script to run. It can automatically request a new access token when ever it needs.
{
"token": "[REDACTED]",
"refresh_token": "[REDACTED]",
"token_uri": "https://oauth2.googleapis.com/token",
"client_id": "[REDACTED]",
"client_secret": "[REDACTED],
"scopes": [
"https://mail.google.com/"
],
"expiry": "2023-01-03T19:06:13.959468Z"
}
gmail quickstart.
# To install the Google client library for Python, run the following command:
# pip install --upgrade google-api-python-client google-auth-httplib2 google-auth-oauthlib
from __future__ import print_function
import os.path
import google.auth.exceptions
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
# If modifying these scopes, delete the file token.json.
SCOPES = ['https://mail.google.com/']
def main():
"""Shows basic usage of the Gmail v1 API.
Prints a list of user messages.
"""
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'):
try:
creds = Credentials.from_authorized_user_file('token.json', SCOPES)
creds.refresh(Request())
except google.auth.exceptions.RefreshError as error:
# if refresh token fails, reset creds to none.
creds = None
print(f'An error occurred: {error}')
# 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(
'C:\YouTube\dev\credentials.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('gmail', 'v1', credentials=creds)
# Call the Gmail v1 API
results = service.users().messages().list(
userId='me').execute()
messages = results.get('messages', [])
if not messages:
print('No messages found.')
return
print('Messages:')
for message in messages:
print(u'{0} ({1})'.format(message['id'], message['threadId']))
except HttpError as error:
# TODO(developer) - Handle errors from gmail API.
print(f'An error occurred: {error}')
if __name__ == '__main__':
main()
expired refresh token.
If your issue is in fact that your refresh tokens are expiring this is because your app is currently in the testing phase. If you set your app to production then your refresh tokens will stope expiring.
I would like to get push notifications anytime a file is added to our shared drive by any user.
I have a service account authenticated with the Google Drive API calling the changes.watch() method on the shared drive, and I successfully get notifications if the shared drive name or icon changes, a file is created by the service account, or if files are modified by any user so long as the service account created the file. However, I do not get any push notifications for files created on this shared drive by other users - even though the page token increases and calling changes.list() will show me the changes that all users made on the shared drive.
I have the shared drive shared with the service account, and the service account also has domain-wide delegation for the scope https://www.googleapis.com/auth/drive and uses that scope in the API call.
Any help would be greatly appreciated as I cannot figure out what I'm lacking to get push notifications for all changes on this shared drive. Below is my code related to authenticating and subscribing to change notifications.
import urllib
from google.oauth2.credentials import Credentials
from googleapiclient.discovery import build
from googleapiclient.errors import HttpError
from google.oauth2 import service_account
import uuid
from datetime import datetime
def get_service(api_name, api_version, scopes, key_file_location):
credentials = service_account.Credentials.from_service_account_file(
key_file_location)
scoped_credentials = credentials.with_scopes(scopes)
service = build(api_name, api_version, credentials=scoped_credentials)
return service
def get_start_page_token(service):
response = service.changes().getStartPageToken(
driveId = "REDACTED",
supportsAllDrives = True,
supportsTeamDrives = True
).execute()
startPageToken = response.get("startPageToken")
print(F'Start token: {startPageToken}')
return startPageToken
def subscribe_changes(service):
channel_id = str(uuid.uuid4())
body = {
"id": channel_id,
"type": "web_hook",
"address": "https://REDACTED"
}
response = service.changes().watch(
body=body,
pageToken = get_start_page_token(service),
includeItemsFromAllDrives = True,
supportsAllDrives = True,
supportsTeamDrives = True,
driveId = "REDACTED"
).execute()
ts = int(response['expiration'])
print("Expiration in UTC: " + datetime.utcfromtimestamp(ts / 1000).strftime('%Y-%m-%d %H:%M:%S'))
print(response)
return channel_id
# Define the auth scopes to request.
scope = 'https://www.googleapis.com/auth/drive'
key_file_location = 'credentials.json'
try:
# Authenticate and construct service.
service = get_service(
api_name='drive',
api_version='v3',
scopes=[scope],
key_file_location=key_file_location)
except HttpError as error:
print(f'An error occurred: {error}')
# subscribe to changes
channel_id = subscribe_changes(service)
print(f"Channel Id: {channel_id}")
I am a beginner programmer. I am trying to work with Google API. I am using the OAuth to send requests to Google Calendar API. However, I get error 403:
{
"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"
}
}
The following question Google Calendar "The request is missing a valid API key" when using OAuth suggests using:
google.calendar({ version: "v3", auth: client })
However my code provided by Google uses:
service = build('calendar', 'v3', credentials=creds)
so the suggested solution is not applicable.
My full code is the same as Google API's provided 'Quickstart.py' except for the name of the client_secre_file:
from __future__ import print_function
import datetime
import os.path
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
# If modifying these scopes, delete the file token.json.
SCOPES = ['https://www.googleapis.com/auth/calendar.readonly']
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_desktop.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'])
except HttpError as error:
print('An error occurred: %s' % error)
if __name__ == '__main__':
main()
Maybe there is an issue in my Credentials configuration?
I'm working on python script which captures all my events in google calendar. this code will show the list of all the events in a day.
Below is the code.
from __future__ import print_function
import httplib2
import os
import datetime
from apiclient import discovery
import oauth2client
from oauth2client import client
from oauth2client import tools
from oauth2client.file import Storage
import datetime
try:
import argparse
flags = argparse.ArgumentParser(parents=[tools.argparser]).parse_args()
except ImportError:
flags = None
# If modifying these scopes, delete your previously saved credentials
# at ~/.credentials/calendar-python-quickstart.json
SCOPES = 'https://www.googleapis.com/auth/calendar.readonly'
CLIENT_SECRET_FILE = 'credentials.json'
APPLICATION_NAME = 'Google Calendar API Python Quickstart'
def get_credentials():
"""Gets valid user credentials from storage.
If nothing has been stored, or if the stored credentials are invalid,
the OAuth2 flow is completed to obtain the new credentials.
Returns:
Credentials, the obtained credential.
"""
home_dir = os.path.expanduser('~')
credential_dir = os.path.join(home_dir, '.credentials')
if not os.path.exists(credential_dir):
os.makedirs(credential_dir)
credential_path = os.path.join(credential_dir,
'calendar-python-quickstart.json')
store = oauth2client.file.Storage(credential_path)
credentials = store.get()
if not credentials or credentials.invalid:
flow = client.flow_from_clientsecrets(CLIENT_SECRET_FILE, SCOPES)
flow.user_agent = APPLICATION_NAME
if flags:
credentials = tools.run_flow(flow, store, flags)
else: # Needed only for compatibility with Python 2.6
credentials = tools.run(flow, store)
print('Storing credentials to ' + credential_path)
return credentials
def main():
"""Shows basic usage of the Google Calendar API.
Creates a Google Calendar API service object and outputs a list of the next
10 events on the user's calendar.
"""
credentials = get_credentials()
http = credentials.authorize(httplib2.Http())
service = discovery.build('calendar', 'v3', http=http)
now = datetime.datetime.utcnow().isoformat() + 'Z' # 'Z' indicates UTC time
print('Getting the upcoming 10 events')
eventsResult = service.events().list(
calendarId='primary', timeMin=now, maxResults=10, singleEvents=True,
orderBy='startTime').execute()
events = eventsResult.get('items', [])
if not events:
print('No upcoming events found.')
for event in events:
start = event['start'].get('dateTime')
# print(start)
start = start[:-9]
# print(start)
start = datetime.datetime.strptime(start,"%Y-%m-%dT%H:%M")
pretty_time = start.strftime("%I:%M")
pretty_date = start.strftime("%B %d, %Y")
print(event['summary'],"at",pretty_time,"on",pretty_date)
if __name__ == '__main__':
main()
below is the error which I'm getting. Not able to find the what is the mistake I made. please help.
below is the error which I'm getting. Not able to find the what is the mistake I made. please help.
Traceback (most recent call last):
File "/Users/mbhamidipati/python-practice/change/getevents.py", line 86, in <module>
main()
File "/Users/mbhamidipati/python-practice/change/getevents.py", line 75, in main
start = start[:-9]
TypeError: 'NoneType' object is not subscriptable
Thanks,
Sreman
It seems that the main thing you need to decide is how you're going to handle when
event['start'].get('dateTime') returns None
you can add a default value to .get('dateTime')
Something like this, assuming that you can get a value from another key, such as 'date'
start = event['start'].get('dateTime', event['start'].get('date'))
I'm trying to write some Python code that creates a calendar (within my own account) and adds events to it.
I keep on getting the following 403 error:
Daily Limit for Unauthenticated Use Exceeded. Continued use requires signup
This does not happen when I create new calendars:
created_calendar = service.calendars().insert(body=calendar).execute()
But the error does come up when I try and create events within the calendar I just made:
event = service.events().insert(calendarId=created_calendar, body=event).execute()
As per other help threads, I've made all of the correct authentications (API key, OAuth, Service Account):
And my daily limit is way beyond the number of requests I've been sending:
I am specifying the OAuth credentials.json file when creating my api client. I am pointing the GOOGLE_APPLICATION_CREDENTIALS environment variable at the service account key (also json) before running.
I'm not sure how else I can authenticate myself...some help would really be appreciated!
EDIT
This is my script (and I believe a minimal example of the error) in case it's helpful:
import datetime
import pytz
import pickle
import os.path
from googleapiclient.discovery import build
from google_auth_oauthlib.flow import InstalledAppFlow
from google.auth.transport.requests import Request
# If modifying these scopes, delete the file token.pickle.
# Add .readonly for read only
SCOPES = ['https://www.googleapis.com/auth/calendar']
def build_cal_service():
creds = None
# The file token.pickle 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.pickle'):
with open('token.pickle', 'rb') as token:
creds = pickle.load(token)
# 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(
'credentials.json', SCOPES)
creds = flow.run_local_server(port=0)
# Save the credentials for the next run
with open('token.pickle', 'wb') as token:
pickle.dump(creds, token)
service = build('calendar', 'v3', credentials=creds)
return service
def main():
service = build_cal_service()
calendar = {
'summary': 'TEST CAL',
'timeZone': 'America/Los_Angeles'
}
created_calendar = service.calendars().insert(body=calendar).execute()
time = datetime.datetime(
year=2019,
month=11,
day=9,
hour=21,
tzinfo=pytz.timezone('US/Pacific'))
event = {
'summary': 'test summary',
'description': 'test description.',
'start': {
'dateTime': time.isoformat(),
},
'end': {
'dateTime': (time + datetime.timedelta(hours=1)).isoformat(),
},
'attendees': [
{'email': 'test1#example.com'},
{'email': 'test2#example.com'},
],
}
event = service.events().insert(calendarId=created_calendar, body=event).execute()
How about this modification?
Unfortunately, in my environment, when I tested your provided script, I couldn't confirm the error of Daily Limit for Unauthenticated Use Exceeded. Continued use requires signup. But I think that in your script, event = service.events().insert(calendarId=created_calendar, body=event).execute() occurs an error. So how about the following modification?
From:
event = service.events().insert(calendarId=created_calendar, body=event).execute()
To:
event = service.events().insert(calendarId=created_calendar['id'], body=event).execute()
Note:
created_calendar of created_calendar = service.calendars().insert(body=calendar).execute() is an object. So when the calendar ID is retrieved, please use created_calendar['id'].
This answer supposes that credentials.json is the file which was downloaded by "Create credentials" at "OAuth client ID".
If the error related to the authorization occurs, please delete the file of token.pickle and run the script, and then authorize again.
References:
Calendars: insert
Events: insert