I am trying to search YouTube for videos using YouTube v3 API in Python with the requirements in the code, but I'm getting this error.
How can I prevent this from happening? This code is from Google too. You can edit the code on the Google website here. I'm a total noob at this so if you have any information I must know for the future, please do say so. Thanks
# -*- coding: utf-8 -*-
# Sample Python code for youtube.search.list
# See instructions for running these code samples locally:
# https://developers.google.com/explorer-help/guides/code_samples#python
import os
import google_auth_oauthlib.flow
import googleapiclient.discovery
import googleapiclient.errors
scopes = ["https://www.googleapis.com/auth/youtube.force-ssl"]
def main():
# Disable OAuthlib's HTTPS verification when running locally.
# *DO NOT* leave this option enabled in production.
os.environ["OAUTHLIB_INSECURE_TRANSPORT"] = "1"
api_service_name = "youtube"
api_version = "v3"
client_secrets_file = "client_secret.json"
# Get credentials and create an API client
flow = google_auth_oauthlib.flow.InstalledAppFlow.from_client_secrets_file(
client_secrets_file, scopes)
credentials = flow.run_console()
youtube = googleapiclient.discovery.build(
api_service_name, api_version, credentials=credentials)
request = api.youtube.search().list(
part="snippet",
location="United States",
maxResults=5,
order="date",
q="programming",
regionCode="US",
relevanceLanguage="en",
safeSearch="none",
videoDimension="any",
videoDuration="any"
)
response = request.execute()
print(response)
if __name__ == "__main__":
main()
error number two
Yeah your code may be from google but you have renamed something.
All your calls need to go though the YouTube serivce object
youtube = googleapiclient.discovery.build(
api_service_name, api_version, credentials=credentials)
Yet you are calling it using api
request = api.youtube.search().list(
it should be
request = youtube.search().list(
Check the code from google again and becameful when you rename things if you don't understand what there used for.
# -*- coding: utf-8 -*-
# Sample Python code for youtube.search.list
# See instructions for running these code samples locally:
# https://developers.google.com/explorer-help/guides/code_samples#python
import os
import google_auth_oauthlib.flow
import googleapiclient.discovery
import googleapiclient.errors
scopes = ["https://www.googleapis.com/auth/youtube.force-ssl"]
def main():
# Disable OAuthlib's HTTPS verification when running locally.
# *DO NOT* leave this option enabled in production.
os.environ["OAUTHLIB_INSECURE_TRANSPORT"] = "1"
api_service_name = "youtube"
api_version = "v3"
client_secrets_file = "YOUR_CLIENT_SECRET_FILE.json"
# Get credentials and create an API client
flow = google_auth_oauthlib.flow.InstalledAppFlow.from_client_secrets_file(
client_secrets_file, scopes)
credentials = flow.run_console()
youtube = googleapiclient.discovery.build(
api_service_name, api_version, credentials=credentials)
request = youtube.search().list(
part="snippet",
location="United States",
maxResults=5,
order="date",
q="Programming",
regionCode="US",
relevanceLanguage="en",
safeSearch="none",
videoDimension="any",
videoDuration="any"
)
response = request.execute()
print(response)
if __name__ == "__main__":
main()
Error number 2
You need to check the parameters you are sending remove location thats not a valid location
Google's youtube Analytics API is Oauth2 based only.
I am using the below test script to see if I can gain access:
import os
import google.oauth2.credentials
import google_auth_oauthlib.flow
from googleapiclient.discovery import build
from googleapiclient.errors import HttpError
from google_auth_oauthlib.flow import InstalledAppFlow
SCOPES = ['https://www.googleapis.com/auth/yt-analytics.readonly']
API_SERVICE_NAME = 'youtubeAnalytics'
API_VERSION = 'v2'
CLIENT_SECRETS_FILE = 'client_secret.json'
def get_service():
flow = InstalledAppFlow.from_client_secrets_file(CLIENT_SECRETS_FILE, SCOPES)
credentials = flow.run_console()
return build(API_SERVICE_NAME, API_VERSION, credentials = credentials)
def execute_api_request(client_library_function, **kwargs):
response = client_library_function(
**kwargs
).execute()
print(response)
if __name__ == '__main__':
# Disable OAuthlib's HTTPs verification when running locally.
# *DO NOT* leave this option enabled when running in production.
os.environ['OAUTHLIB_INSECURE_TRANSPORT'] = '1'
youtubeAnalytics = get_service()
execute_api_request(
youtubeAnalytics.reports().query,
ids='channel==MINE',
startDate='2017-01-01',
endDate='2017-12-31',
metrics='estimatedMinutesWatched,views,likes,subscribersGained',
dimensions='day',
sort='day'
)
my problem is that this script requres me to open a browser, set a link, login, then get a token cable.
Is there ANY way to do this in a "headless" mode?
I need to pull these APIs for machine-to-machine transfer.
Thanks!
Do it once, then save the credentials object returned by credentials = flow.run_console() to either a database or a file. This contains a "refresh token" which can be used in subsequent api calls, meaning you can skip the flow.run_console step, and just use the saved credentials in a build(API_SERVICE_NAME, API_VERSION, credentials = credentials) call.
There's a note about this in the docs here:
https://developers.google.com/youtube/reporting/guides/authorization/installed-apps#exchange-authorization-code
Following is the code to access a google storage bucket using the httplib2 library
import json
from httplib2 import Http
from oauth2client.client import SignedJwtAssertionCredentials
from googleapiclient.discovery import build
from pprint import pprint
client_email = 'my.iam.gserviceaccount.com'
json_file = 'services.json'
cloud_storage_bucket = 'my_bucket'
files = 'reviews/reviews_myapp_201603.csv'
private_key = json.loads(open(json_file).read())['private_key']
credentials = SignedJwtAssertionCredentials(client_email,
private_key,'https://www.googleapis.com/auth/devstorage.read_only')
storage = build('storage', 'v1', http=credentials.authorize(Http()))
pprint(storage.objects().get(bucket=cloud_storage_bucket, object=files).execute())
Can someone tell me if I can make the http request using the Python Requests library here?
If yes, how?
Yes, you can use the HTTP header Authorization: Bearer <access_token> with requests or any library you want.
Service account
from google.oauth2 import service_account
credentials = service_account.Credentials.from_service_account_file(
'services.json',
scopes=['https://www.googleapis.com/auth/devstorage.read_only'],
)
# Copy access token
bearer_token = credentials.token
User account credentials
import json
from google.oauth2.credentials import Credentials
from google_auth_oauthlib.flow import InstalledAppFlow
flow = InstalledAppFlow.from_client_secrets_file(
'test.json',
'https://www.googleapis.com/auth/devstorage.read_only'
)
# Construct cache path for oauth2 token
oauth2_cache_path = 'test-oauth2.json'
credentials = None
try:
# Try to load existing oauth2 token
with open(oauth2_cache_path, 'r') as f:
credentials = Credentials(**json.load(f))
except (OSError, IOError) as e:
pass
if not credentials or not credentials.valid:
credentials = flow.run_console()
with open(oauth2_cache_path, 'w+') as f:
f.write(json.dumps({
'token': credentials.token,
'refresh_token': credentials.refresh_token,
'token_uri': credentials.token_uri,
'client_id': credentials.client_id,
'client_secret': credentials.client_secret,
'scopes': credentials.scopes,
}))
# Copy access token
bearer_token = credentials.token
Use requests lib
import requests
# Send request
response = requests.get(
'https://www.googleapis.com/storage/v1/<endpoint>?access_token=%s'
% bearer_token)
# OR
response = requests.get(
'https://www.googleapis.com/storage/v1/<endpoint>',
headers={'Authorization': 'Bearer %s' % bearer_token})
Use googleapiclient lib
I recommend you to use build() method and not requests directly because the google library do some checks before sending your API call (like checking params, endpoint, auth and the method you use). This library also raise exceptions when error is detected.
from googleapiclient.discovery import build
storage = build('storage', 'v1', credentials=credentials)
print(storage.objects().get(bucket='bucket', object='file_path').execute())
More informations here : https://developers.google.com/identity/protocols/OAuth2WebServer#callinganapi (click on "HTTP/REST" tab)
I suggest to use the official Google Auth library which is already implementing Requests Library. See this link for more information.
Here is a code to try (given that you have a service account file with required permissions):
from google.oauth2 import service_account
from google.auth.transport.requests import AuthorizedSession
service_account_file = 'service_account.json'
scopes = ['https://www.googleapis.com/auth/devstorage.full_control']
credentials = service_account.Credentials.from_service_account_file(
service_account_file, scopes=scopes)
session = AuthorizedSession(credentials)
bucket_name = 'YOUR-BUCKET-NAME'
response = session.get(f'https://storage.googleapis.com/storage/v1/b/{bucket_name}')
print(response.json())
The Google Sheets API Python Quickstart currently uses deprecated packages in its example code, where the use of oauth2client and httplib2 rather than google-auth and google-auth-oauthlib (or maybe google-auth?) is outdated or soon to be.
How do I rewrite this code to use these new libraries in a way that best anticipates their current state and the eventual move to google-auth, etc.? In particular, is there a simple reimplementation of retrieval, storage, and use of credentials in the quickstart (below) that brings it up to date?
from __future__ import print_function
import httplib2
import os
from apiclient import discovery
from oauth2client import client
from oauth2client import tools
from oauth2client.file import Storage
try:
import argparse
flags = argparse.ArgumentParser(parents=[tools.argparser]).parse_args()
except ImportError:
flags = None
SCOPES = 'https://www.googleapis.com/auth/spreadsheets.readonly'
CLIENT_SECRET_FILE = 'client_secret.json'
APPLICATION_NAME = 'Google Sheets API Python Quickstart'
def get_credentials():
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, 'sheets.googleapis.com-python-quickstart.json')
store = 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():
credentials = get_credentials()
http = credentials.authorize(httplib2.Http())
discoveryUrl = 'https://sheets.googleapis.com/$discovery/rest?version=v4'
service = discovery.build('sheets', 'v4', http=http, discoveryServiceUrl=discoveryUrl)
# etc. ...
How about this answer? I prepared the sample script for the Quickstart of Sheets API.
In this sample, it supposes below.
Sheet API is enabled
You have a client_secret.json.
In this sample, at first, refresh token is retrieved using authorization code. The refresh token is saved to sheets.googleapis.com-python-quickstart.json. After 1st run, the access token is retrieved by the refresh token.
In this sample, cell values are retrieved from spreadsheet.
Sample script :
import copy
import json
import os
import pprint
import google.oauth2.credentials
from googleapiclient.discovery import build
from google_auth_oauthlib.flow import InstalledAppFlow
pp = pprint.PrettyPrinter(indent=2)
CLIENT_SECRETS_FILE = "client_secret.json"
SCOPES = ['https://www.googleapis.com/auth/spreadsheets.readonly']
API_SERVICE_NAME = 'sheets'
API_VERSION = 'v4'
def get_authenticated_service():
credential_path = os.path.join("./", 'sheets.googleapis.com-python-quickstart.json')
if os.path.exists(credential_path):
with open(credential_path, 'r') as f:
credential_params = json.load(f)
credentials = google.oauth2.credentials.Credentials(
credential_params["access_token"],
refresh_token=credential_params["refresh_token"],
token_uri=credential_params["token_uri"],
client_id=credential_params["client_id"],
client_secret=credential_params["client_secret"]
)
else:
flow = InstalledAppFlow.from_client_secrets_file(CLIENT_SECRETS_FILE, SCOPES)
credentials = flow.run_console()
with open(credential_path, 'w') as f:
p = copy.deepcopy(vars(credentials))
del p["expiry"]
json.dump(p, f, indent=4)
return build(API_SERVICE_NAME, API_VERSION, credentials=credentials)
def spreadsheets_get(service):
spreadsheetId = "### spreadsheet ID ###"
rangeName = "Sheet1!a1:a10"
results = service.spreadsheets().get(
spreadsheetId=spreadsheetId,
ranges=rangeName
).execute()
pp.pprint(results)
if __name__ == '__main__':
os.environ['OAUTHLIB_INSECURE_TRANSPORT'] = '1'
service = get_authenticated_service()
spreadsheets_get(service)
Note :
In order to save credentials, it was required to use oauth2client.file. So I prepared the sample script without using oauth2client.file. If you want to use oauth2client.file, please modify it.
I think that Quickstart for Sheets API may be also updated in the near future.
References :
References I refered to prepare this sample script are as follows.
Using OAuth 2.0 for Installed Applications
There is a sample script for python.
User Guide
google.oauth2.credentials module
Using OAuth 2.0 for Web Server Applications
If I misunderstand your question, I'm sorry.
I am using googles official oauth2client.client to access the google
plus api. I have a refresh token (that does not expire) stored in a database, and need
to recreate the temporary "Credentials" (access token) from that.
But I could not find a way to do this with to official library supplied by google.
So I hacked around it: used urllib to access the API that gives me a new
access_token from the refresh_token. Using the access_token I can then use the library.
I must be missing somthing!
from apiclient import discovery
from oauth2client.client import AccessTokenCredentials
from urllib import urlencode
from urllib2 import Request , urlopen, HTTPError
import json
# ==========================================
def access_token_from_refresh_token(client_id, client_secret, refresh_token):
request = Request('https://accounts.google.com/o/oauth2/token',
data=urlencode({
'grant_type': 'refresh_token',
'client_id': client_id,
'client_secret': client_secret,
'refresh_token': refresh_token
}),
headers={
'Content-Type': 'application/x-www-form-urlencoded',
'Accept': 'application/json'
}
)
response = json.load(urlopen(request))
return response['access_token']
# ==========================================
access_token = access_token_from_refresh_token(CLIENT_ID, CLIENT_SECRET, REFRESH_TOKEN)
# now I can use the library properly
credentials = AccessTokenCredentials(access_token, "MyAgent/1.0", None)
http = credentials.authorize(httplib2.Http())
service = discovery.build('plus', 'v1', http=http)
google_request = service.people().get(userId='me')
result = google_request.execute(http=http)
I use: oauth2client.client.GoogleCredentials
cred = oauth2client.client.GoogleCredentials(access_token,client_id,client_secret,
refresh_token,expires_at,"https://accounts.google.com/o/oauth2/token",some_user_agent)
http = cred.authorize(httplib2.Http())
cred.refresh(http)
self.gmail_service = discovery.build('gmail', 'v1', credentials=cred)
You can construct an OAuth2Credentials instance directly like this:
import httplib2
from oauth2client import GOOGLE_REVOKE_URI, GOOGLE_TOKEN_URI, client
CLIENT_ID = '<client_id>'
CLIENT_SECRET = '<client_secret>'
REFRESH_TOKEN = '<refresh_token>'
credentials = client.OAuth2Credentials(
access_token=None, # set access_token to None since we use a refresh token
client_id=CLIENT_ID,
client_secret=CLIENT_SECRET,
refresh_token=REFRESH_TOKEN,
token_expiry=None,
token_uri=GOOGLE_TOKEN_URI,
user_agent=None,
revoke_uri=GOOGLE_REVOKE_URI)
credentials.refresh(httplib2.Http()) # refresh the access token (optional)
print(credentials.to_json())
http = credentials.authorize(httplib2.Http()) # apply the credentials
I solved this quite easily (you certainly miss this documentation). This is a snippet of my code that tries to use Picasa API to get all of album from active user:
http = httplib2.Http(ca_certs=os.environ['REQUESTS_CA_BUNDLE'])
try:
http = self.oauth.credentials.authorize(http)
response, album_list = http.request(Picasa.PHOTOS_URL, 'GET')
if response['status'] == '403':
self.oauth.credentials.refresh(http)
response, album_list = http.request(Picasa.PHOTOS_URL, 'GET')
album_list = json.load(StringIO(album_list))
except Exception as ex:
Logger.debug('Picasa: error %s' % ex)
return {}
Use the refresh method coming from oauth2client.client.OAuth2Credentials. I think it's even okay to use if response['status'] != '200'. Got to check that!
You can also use the requests library as well:
import google.auth.transport.requests
import requests
request = google.auth.transport.requests.Request()
credentials.refresh(request)
Here is my sample code on an active project:
acct_creds = {
'token': self.attachment.account.google_drive_access_token,
'refresh_token': self.attachment.account.google_drive_refresh_token,
'client_id': settings.GOOGLE_CLIENT_ID,
'client_secret': settings.GOOGLE_CLIENT_SECRET,
'token_uri': 'https://37947.ngrok.io/authenticate/google/callback/',
'scopes': 'https://www.googleapis.com/auth/drive.appdata https://www.googleapis.com/auth/drive.file https://www.googleapis.com/auth/drive.install',
}
credentials = google.oauth2.credentials.Credentials(**acct_creds)
if credentials.valid:
print("Credentials valid")
else:
request = google.auth.transport.requests.Request()
credentials.refresh(request)
google.auth.transport.requests module
In case anyone is looking for the answer for how use a refresh token with google_auth_oauthlib, the following works for me:
flow.oauth2session.refresh_token(flow.client_config['token_uri'],
refresh_token=refresh_token,
client_id=<MY_CLIENT_ID>,
client_secret=flow.client_config['client_secret'])
creds = google_auth_oauthlib.helpers.credentials_from_session(
flow.oauth2session, flow.client_config)
I cannot find anywhere where this is documented though.
If you are using the 2018 Youtube Python Quickstart demo app using google-auth, you can't use oauth2client's storage.
So here is the correct way of storing the credentials
Here is a partially working solution for google-auth, missing the correct handling of the case where the token expires:
import os
import json
import os.path
import google.oauth2.credentials
from google.oauth2.credentials import Credentials
from googleapiclient.discovery import build
from googleapiclient.errors import HttpError
from google_auth_oauthlib.flow import InstalledAppFlow
CLIENT_SECRETS_FILE = "client_secret.json"
SCOPES = ['https://www.googleapis.com/auth/youtube.force-ssl']
API_SERVICE_NAME = 'youtube'
API_VERSION = 'v3'
def get_authenticated_service():
if os.path.isfile("credentials.json"):
with open("credentials.json", 'r') as f:
creds_data = json.load(f)
creds = Credentials(creds_data['token'])
else:
flow = InstalledAppFlow.from_client_secrets_file(CLIENT_SECRETS_FILE, SCOPES)
creds = flow.run_console()
creds_data = {
'token': creds.token,
'refresh_token': creds.refresh_token,
'token_uri': creds.token_uri,
'client_id': creds.client_id,
'client_secret': creds.client_secret,
'scopes': creds.scopes
}
print(creds_data)
with open("credentials.json", 'w') as outfile:
json.dump(creds_data, outfile)
return build(API_SERVICE_NAME, API_VERSION, credentials = creds)
def channels_list(service, **kwargs):
results = service.channels().list(**kwargs).execute()
print('This channel\'s ID is %s. Its title is %s, and it has %s views.' %
(results['items'][0]['id'],
results['items'][0]['snippet']['title'],
results['items'][0]['statistics']['viewCount']))
if __name__ == '__main__':
os.environ['OAUTHLIB_INSECURE_TRANSPORT'] = '1'
service = get_authenticated_service()
channels_list(service, part='snippet,contentDetails,statistics', forUsername='GoogleDevelopers')
# or if the above doesn't work
channels_list(service, part='snippet,contentDetails,statistics', id='YOUR_YOUTUBE_CHANNEL_ID')
I recommend this method.
from oauth2client import client, GOOGLE_TOKEN_URI
CLIENT_ID = "client_id"
CLIENT_SECRET = "client_secret"
REFRESH_TOKEN = "refresh_token"
credentials = client.OAuth2Credentials(
access_token = None,
client_id = CLIENT_ID,
client_secret = CLIENT_SECRET,
refresh_token = REFRESH_TOKEN,
token_expiry = None,
token_uri = GOOGLE_TOKEN_URI,
token_ id = None,
revoke_uri= None)
http = credentials.authorize(httplib2.Http())
Even if the access token has expired, the credential is still authorize because of the refresh token.
If you have a refresh token then you can generate credentials for use by using OAuth2Credentials as below
from googleapiclient.discovery import build
import httplib2
from oauth2client import client, GOOGLE_TOKEN_URI
client_id = "YOUR_CLIENT_ID"
client_secret = "YOUR_CLIENT_SECRET"
refresh_token = "YOUR_REFRESH_TOKEN"
creds = client.OAuth2Credentials(
access_token = None,
client_id = client_id,
client_secret = client_secret,
refresh_token = refresh_token,
token_expiry = None,
token_uri = GOOGLE_TOKEN_URI,
user_agent="pythonclient")
creds.refresh(httplib2.Http())
I don't know what goes in the user agent but I put a random word in there
Now you can use it to build service object and use google APIs like
service = build("drive", "v3", credentials=creds)
In case someone wants to generate and use a offline refresh token for use without having to handle the autorization since it's for your testing then use google oauth playground to generate one. Checkout this video for more information.
You could store the entire credentials rather than only the refresh token:
json = credentials.to_json()
credentials = Credentials.new_from_json(json)
Look at the Storage object which does it this way.
Wow.. 2 years old question and not a good answer.. No surprise given that Google documentation is crap regarding this.
The correct way to do this is by extending the Storage class oauth2client.client.Storage
An example implementation(using mongodb collection _google_credentials) would be something like:
class Storage(oauth2client.client.Storage):
def __init__(self, key):
super(Storage, self).__init__()
self._key = key
def locked_get(self):
if not self._key: return None
data = _google_credentials.find_one({'_id': self._key})
if not data: return None
credentials = oauth2client.client.Credentials.new_from_json(json.dumps(data))
credentials.set_store(self)
return credentials
def locked_put(self, credentials):
data = json.loads(credentials.to_json())
_google_credentials.update_one({'_id': self._key}, {'$set': data},
upsert=True)
credentials.set_store(self)
def locked_delete(self):
bucket.delete(self._key)
Then when you initially get the credentials after step2_exchange, you need to store them using Storage().put:
e.g:
credentials = flow.step2_exchange(code)
Storage(user_id).put(credentials)
When you need the credentials again, just do:
credentials = Storage(user_id).get()
If you already have a Credentials object then you can refresh it like so:
if refresh:
import google_auth_httplib2
# credentials instanceof google.oauth2.credentials.Credentials
credentials.refresh(google_auth_httplib2.Request(httplib2.Http()))
I had created the Credentials object from an old token JSON file like so:
credentials = google.oauth2.credentials.Credentials(
token=token_json['access_token'],
refresh_token=token_json['refresh_token'],
id_token=token_json['id_token'],
token_uri=token_json['token_uri'],
client_id=token_json['client_id'],
client_secret=token_json['client_secret'],
scopes=token_json['scopes'])
In this way I was able to adapt some old oauth2client code.