I am Trying to use the youtube-api V3 search. I have a flask web application and am trying to output the results into rows on the webpage.
I started with the Google developers pages (works perfect in terminal) then found this great sounding example which would output thumbnails and hyper links from the results. However it ran on Google app engine and I am trying to create a Flask application.
So with my very limited knowledge I have tried to merge them to fit my needs.
#!/usr/bin/python
from apiclient.discovery import build
from apiclient.errors import HttpError
from oauth2client.tools import argparser
import sys
import os
import urllib
# Set API_KEY to the "API key" value from the "Access" tab of the
# Google APIs Console http://code.google.com/apis/console#access
# Please ensure that you have enabled the YouTube Data API and Freebase API
# for your project.
API_KEY = "REPLACE ME" #Yes I did replace this with my API KEY
YOUTUBE_API_SERVICE_NAME = "youtube"
YOUTUBE_API_VERSION = "v3"
QUERY_TERM = "dog"
def search_by_keyword():
youtube = build(
YOUTUBE_API_SERVICE_NAME,
YOUTUBE_API_VERSION,
developerKey=API_KEY
)
search_response = youtube.search().list(
q=QUERY_TERM,
part="id,snippet",
maxResults=25
).execute()
videos = []
for search_result in search_response.get("items", []):
if search_result["id"]["kind"] == "youtube#video":
videos.append("%s (%s)" % (search_result["snippet"]["title"],
search_result["id"]["videoId"]))
print "Videos:\n", "\n".join(videos), "\n"
if __name__ == "__main__":
try:
youtube_search()
except HttpError, e:
print "An HTTP error %d occurred:\n%s" % (e.resp.status, e.content)
What I actually want it to do is return results to my webpage rather than just print but thought it was best to take one step at a time. If I can make it work in terminal I could then sort it on a webpage, but not as simple as I thought.
Currently I receive error;
Traceback (most recent call last):
File "search.py", line 38, in <module>
print "Videos:\n", "\n".join(videos), "\n"
NameError: name 'videos' is not defined
Which is my first main hurdle as I was expecting it to work as it did in both examples I took it from.
My second problem is how do I go about converting results (assuming I could fix above) into a table on the webpage?
I plan to have
#app.route('/search')
include the above code and then;
return render_template ('search.html')
But unsure how to pass the results back onto it, do I still need the print for this or is it another term I should be using? I want to be able to use the VideoID returned from each to sort thumbnails and links.
your list of videos is a local variable and doesn't exist outside your function "search_by_keyword()" to access the videos variable, you could return that variable like so:
def search_by_keyword():
youtube = build(
YOUTUBE_API_SERVICE_NAME,
YOUTUBE_API_VERSION,
developerKey=API_KEY
)
search_response = youtube.search().list(
q=QUERY_TERM,
part="id,snippet",
maxResults=25
).execute()
videos = []
for search_result in search_response.get("items", []):
if search_result["id"]["kind"] == "youtube#video":
videos.append("%s (%s)" % (search_result["snippet"]["title"],
search_result["id"]["videoId"]))
return videos
in your main function you could use something like:
videos = search_by_keyword()
in that way you could print the videos to the console or send it to a template with Flask.
Related
I'm trying to use the aforementioned API to get number of google search results for a query, however it's not giving me the correct results. I have my custom search engine configured to search the entire web. For example, if I search "hello" I get 113,000,000 results. However if I do that myself on Google I get 1,340,000,000. I'm quite new to all this stuff so feeling quite lost, can anybody please help? Thanks
from googleapiclient.discovery import build
import pprint
my_api_key = "API KEY"
my_cse_id = "CSE ID"
def main():
service = build("customsearch", "v1",
developerKey = my_api_key)
res = service.cse().list(q = 'hello', cx= my_cse_id,).execute()
pprint.pprint(res)
if __name__ == '__main__':
main()
I have a little application based on google-api-python-client, but the batch request has not been working anymore for a couple of days (error 404).
For example, the following code worked fine until a few days ago.
from apiclient.http import BatchHttpRequest
from apiclient.discovery import build
import json
DEVELOPER_KEY = "foobar"
YOUTUBE_API_SERVICE_NAME = "youtube"
YOUTUBE_API_VERSION = "v3"
channelIds = ['UC2C_jShtL725hvbm1arSV9w','UC2C_jShtL725hvbm1arSV9w']
parts_list = [
"id",
"brandingSettings",
]
fields_list = [
"items/id",
"items/brandingSettings/channel",
]
parts = ",".join(parts_list)
fields = ",".join(fields_list)
request_map = {}
def this_is_the_callback_function(request_id, response, exception):
if exception is not None:
# Do something with the exception
print exception
pass
else:
print request_id
print request_map[int(request_id)]
print json.dumps(response,sort_keys=True, indent=4)
service = build(YOUTUBE_API_SERVICE_NAME, YOUTUBE_API_VERSION, developerKey=DEVELOPER_KEY)
batch = service.new_batch_http_request(callback=this_is_the_callback_function)
channels = service.channels()
i = 0
for c in channelIds:
i += 1
request_map[i] = c
request = channels.list(id=c,part=parts, fields=fields)
batch.add(request)
print request_map
batch.execute()
Now, If i run it, I get:
{1: 'UC2C_jShtL725hvbm1arSV9w', 2: 'UC2C_jShtL725hvbm1arSV9w'}
<HttpError 404 when requesting https://www.googleapis.com/youtube/v3/channels?fields=items%2Fid%2Citems%2FbrandingSettings%2Fchannel&alt=json&part=id%2CbrandingSettings&id=UC2C_jShtL725hvbm1arSV9w&key=foobar returned "Not Found">
<HttpError 404 when requesting https://www.googleapis.com/youtube/v3/channels?fields=items%2Fid%2Citems%2FbrandingSettings%2Fchannel&alt=json&part=id%2CbrandingSettings&id=UC2C_jShtL725hvbm1arSV9w&key=foobar returned "Not Found">
Strange. What it seems odd to me is that If I try to make a simple request to those links (simply by cutting and pasting an URL in the browser), the server returns data as usual.
It seems this problem is fixed with the newest version of the python library.
However, if someone still has to solve it, or is using a different environment (like iOS or android), that's the solution.
it seems google have used before a single batch url, which was:
https://www.googleapis.com/batch
this worked well in my apps, until it suddenly stopped. it seems the solution is to change the url for the batch calls to :
https://www.googleapis.com/batch/youtube/v3
(for youtube apis)
usually the google api objects will expose a property allowing to change this value, but if not it can be changed in source.
Reporting a possible bug on Youtube Api commentThreads.update
Name of API affected: CommentThreads: update
Issue summary: CommentThreads: update When calling this api to update the topLevelComment returned by CommentThreads.list, I got a 400 error. I was using this API in an internal tool to allow me respond to comments. It was working fine for the last months... and in the last days (~2016-11-07) with no changes on any code on my side, the API started to return a 400 error. I have all my internal comment systems halted right now as I could not figure out how to fix this. Every thing I tried and tested brings me to the 400 error and the message below.
"While this can be a transient error, it usually indicates that the requests input is invalid."
Even using the API console, I got the same errror!
My bet? This is a transient error that I hope Google can fix.
Steps to reproduce issue:
Retrieve "heldForReview" threads using CommentThreads.list
Try to update the returned topLevelComment changing ["topLevelComment"]["snippet"]["textOriginal"] = "some text". Optionally, change the "moderationStatus" to "published". The error is the same.
This behaviour can be easily spotted using the Python API samples, specifically the file comment_threads.py from https://github.com/youtube/api-samples/blob/master/python/comment_threads.py
Expected output: The top level comment from Thread should become visible (after setting the moderationStatus to published) and have the "some text" as the first child comment as its answer.
Actual results:
{
"error": {
"errors": [
{
"domain": "youtube.commentThread",
"reason": "processingFailure",
"message": "The API server failed to successfully process the request. While this can be a transient error, it usually indicates that the requests input is invalid. Check the structure of the \u003ccode\u003ecommentThread\u003c/code\u003e resource in the request body to ensure that it is valid.",
"locationType": "other",
"location": "body"
}
],
"code": 400,
"message": "The API server failed to successfully process the request. While this can be a transient error, it usually indicates that the requests input is invalid. Check the structure of the \u003ccode\u003ecommentThread\u003c/code\u003e resource in the request body to ensure that it is valid."
}
}
Notes: I am providing a sample code below.
#!/usr/bin/python
# Usage example:
# python comment_threads.py --channelid='<channel_id>' --videoid='<video_id>' --text='<text>'
import httplib2
import os
import sys
from apiclient.discovery import build_from_document
from apiclient.errors import HttpError
from oauth2client.client import flow_from_clientsecrets
from oauth2client.file import Storage
from oauth2client.tools import argparser, run_flow
# The CLIENT_SECRETS_FILE variable specifies the name of a file that contains
# the OAuth 2.0 information for this application, including its client_id and
# client_secret. You can acquire an OAuth 2.0 client ID and client secret from
# the {{ Google Cloud Console }} at
# {{ https://cloud.google.com/console }}.
# Please ensure that you have enabled the YouTube Data API for your project.
# For more information about using OAuth2 to access the YouTube Data API, see:
# https://developers.google.com/youtube/v3/guides/authentication
# For more information about the client_secrets.json file format, see:
# https://developers.google.com/api-client-library/python/guide/aaa_client_secrets
CLIENT_SECRETS_FILE = "client_secrets.json"
# This OAuth 2.0 access scope allows for full read/write access to the
# authenticated user's account and requires requests to use an SSL connection.
YOUTUBE_READ_WRITE_SSL_SCOPE = "https://www.googleapis.com/auth/youtube.force-ssl"
YOUTUBE_API_SERVICE_NAME = "youtube"
YOUTUBE_API_VERSION = "v3"
# This variable defines a message to display if the CLIENT_SECRETS_FILE is
# missing.
MISSING_CLIENT_SECRETS_MESSAGE = """
WARNING: Please configure OAuth 2.0
To make this sample run you will need to populate the client_secrets.json file
found at:
%s
with information from the APIs Console
https://console.developers.google.com
For more information about the client_secrets.json file format, please visit:
https://developers.google.com/api-client-library/python/guide/aaa_client_secrets
""" % os.path.abspath(os.path.join(os.path.dirname(__file__),CLIENT_SECRETS_FILE))
# Authorize the request and store authorization credentials.
def get_authenticated_service(args):
flow = flow_from_clientsecrets(CLIENT_SECRETS_FILE, scope=YOUTUBE_READ_WRITE_SSL_SCOPE,message=MISSING_CLIENT_SECRETS_MESSAGE)
storage = Storage("%s-oauth2.json" % sys.argv[0])
credentials = storage.get()
if credentials is None or credentials.invalid:
credentials = run_flow(flow, storage, args)
# Trusted testers can download this discovery document from the developers page
# and it should be in the same directory with the code.
with open("youtube-v3-discoverydocument.json", "r") as f:
doc = f.read()
return build_from_document(doc, http=credentials.authorize(httplib2.Http()))
# Call the API's commentThreads.list method to list the existing comments.
def get_comments(youtube, video_id, channel_id):
results = youtube.commentThreads().list(
part="snippet",
videoId=video_id,
channelId=channel_id,
# ONLY FILTER COMMENTS THAT ARE HELD FOR REVIEW
# THOSE COMMENTS ONLY HAVE ONE TOP LEVEL COMMENT
moderationStatus="heldForReview",
textFormat="plainText").execute()
for item in results["items"]:
comment = item["snippet"]["topLevelComment"]
author = comment["snippet"]["authorDisplayName"]
text = comment["snippet"]["textDisplay"]
print "Comment by %s: %s" % (author, text)
return results["items"]
# Call the API's commentThreads.insert method to insert a comment.
def insert_comment(youtube, channel_id, video_id, text):
insert_result = youtube.commentThreads().insert(
part="snippet",
body=dict(
snippet=dict(
channelId=channel_id,
videoId=video_id,
topLevelComment=dict(
snippet=dict(
textOriginal=text
)
)
)
)
).execute()
comment = insert_result["snippet"]["topLevelComment"]
author = comment["snippet"]["authorDisplayName"]
text = comment["snippet"]["textDisplay"]
print "Inserted comment for %s: %s" % (author, text)
# Call the API's commentThreads.update method to update an existing comment.
def update_comment(youtube, comment):
comment["snippet"]["topLevelComment"]["snippet"]["textOriginal"] = 'updated'
update_result = youtube.commentThreads().update(
part="snippet",
body=comment
).execute()
comment = update_result["snippet"]["topLevelComment"]
author = comment["snippet"]["authorDisplayName"]
text = comment["snippet"]["textDisplay"]
print "Updated comment for %s: %s" % (author, text)
if __name__ == "__main__":
# The "channelid" option specifies the YouTube channel ID that uniquely
# identifies the channel for which the comment will be inserted.
argparser.add_argument("--channelid",
help="Required; ID for channel for which the comment will be inserted.")
# The "videoid" option specifies the YouTube video ID that uniquely
# identifies the video for which the comment will be inserted.
argparser.add_argument("--videoid",
help="Required; ID for video for which the comment will be inserted.")
# The "text" option specifies the text that will be used as comment.
argparser.add_argument("--text", help="Required; text that will be used as comment.")
args = argparser.parse_args()
if not args.channelid:
exit("Please specify channelid using the --channelid= parameter.")
if not args.videoid:
exit("Please specify videoid using the --videoid= parameter.")
if not args.text:
exit("Please specify text using the --text= parameter.")
youtube = get_authenticated_service(args)
try:
# All the available methods are used in sequence just for the sake of an example.
# Insert channel comment by omitting videoId
# REMOVED AS IT IS NOT RELEVANT TO THE ERRRO REPORT. insert_comment(youtube, args.channelid, None, args.text)
# Insert video comment
# REMOVED AS IT IS NOT RELEVANT TO THE ERRRO REPORT. insert_comment(youtube, args.channelid, args.videoid, args.text)
video_comments = get_comments(youtube, args.videoid, None)
if video_comments:
update_comment(youtube, video_comments[0])
except HttpError, e:
print "An HTTP error %d occurred:\n%s" % (e.resp.status, e.content)
else:
print "Inserted, listed and updated top-level comments."
Of course, you will need your authorization files inside the same directory.
I am using the following code snipped from Google Developers site. It's working fine but when I search for term shukareh alla, I get ZERO results. The term is misspelled actually, but I want to get the results for the misspelled terms as well just like YouTube website is providing me results for the above term. I don't know whether I should specify some additional parameter for this to work or YouTube API doesn't provide this feature?
from apiclient.discovery import build
from apiclient.errors import HttpError
from oauth2client.tools import argparser
DEVELOPER_KEY = "***************"
YOUTUBE_API_SERVICE_NAME = "youtube"
YOUTUBE_API_VERSION = "v3"
def youtube_search(options):
youtube = build(YOUTUBE_API_SERVICE_NAME, YOUTUBE_API_VERSION,
developerKey=DEVELOPER_KEY)
# Call the search.list method to retrieve results matching the specified
# query term.
search_response = youtube.search().list(
q=options.q,
part="id,snippet",
maxResults=options.max_results
).execute()
videos = []
channels = []
playlists = []
# Add each result to the appropriate list, and then display the lists of
# matching videos, channels, and playlists.
for search_result in search_response.get("items", []):
if search_result["id"]["kind"] == "youtube#video":
videos.append("%s (%s)" % (search_result["snippet"]["title"],
search_result["id"]["videoId"]))
elif search_result["id"]["kind"] == "youtube#channel":
channels.append("%s (%s)" % (search_result["snippet"]["title"],
search_result["id"]["channelId"]))
elif search_result["id"]["kind"] == "youtube#playlist":
playlists.append("%s (%s)" % (search_result["snippet"]["title"],
search_result["id"]["playlistId"]))
print "Videos:\n", "\n".join(videos), "\n"
print "Channels:\n", "\n".join(channels), "\n"
print "Playlists:\n", "\n".join(playlists), "\n"
if __name__ == "__main__":
argparser.add_argument("--q", help="Search term", default="shukareh alla")
argparser.add_argument("--max-results", help="Max results", default=10)
args = argparser.parse_args()
try:
youtube_search(args)
except HttpError, e:
print "An HTTP error %d occurred:\n%s" % (e.resp.status, e.content)
Search: list Returns a collection of search results that match the query parameters specified in the API request.
q string The q parameter specifies the query term to search for. Your
request can also use the Boolean NOT (-) and OR (|) operators to
exclude videos or to find videos that are associated with one of
several search terms. For example, to search for videos matching
either "boating" or "sailing", set the q parameter value to
boating|sailing. Similarly, to search for videos matching either
"boating" or "sailing" but not "fishing", set the q parameter value to
boating|sailing -fishing. Note that the pipe character must be
URL-escaped when it is sent in your API request. The URL-escaped value
for the pipe character is %7C.
The YouTube API will return any results for the request you send. It is not going to spell check it for you. Your application will have to check the spelling then send the correct spelling to the YouTube API.
Answer: The YouTube API does not offer a spellcheck search ability.
Looks like there are 0 results to me.
As said by DaImTo, the Youtube API doesn't provide any spellcheck search ability. I was able to do a spell check using Google Custom Search Engine API. I have created a custom site search engine for site "youtube.com". Whenever I get zero results for Youtube search (using Youtube API), I use the Custom Search API to search for the same keyword. The best thing about the Custom Search Engine API is that, if it gets zero results for a search keyword and the search keyword is incorrect, it does a spell check and returns the corrected search query.
I am just starting with the Google Analytics Reporting API and used the Hello API tutorial to get started. (https://developers.google.com/analytics/solutions/articles/hello-analytics-api)
Unfortunately, I am stuck before I even start. I read it (twice). Created the project, updates the client_secrets.jason file... but when I run the main, it crashes.
File "C:\Python27\New Libraries Downloaded\analytics-v3-python-cmd-line\hello_analytics_api_v3.py", line 173, in <module>
main(sys.argv)
File "C:\Python27\New Libraries Downloaded\analytics-v3-python-cmd-line\hello_analytics_api_v3.py", line 56, in main
service, flags = sample_tools.init(argv, 'analytics', 'v3', __doc__, __file__, scope='https://www.googleapis.com/auth/analytics.readonly')
NameError: global name '__file__' is not defined
I'm new (really really new) to this, so any help (and a more detailed tutorial) would be much appreciated.
Thanks !
EDIT: I have't changed anything from the original code in the tutorial. I'll worry about modifications after I get this running. Thanks !
CODE: hello_analytics_api_v3.py
import argparse
import sys
from apiclient.errors import HttpError
from apiclient import sample_tools
from oauth2client.client import AccessTokenRefreshError
def main(argv):
# Authenticate and construct service.
service, flags = sample_tools.init(argv, 'analytics', 'v3', __doc__, __file__, scope='https://www.googleapis.com/auth/analytics.readonly')
# Try to make a request to the API. Print the results or handle errors.
try:
first_profile_id = get_first_profile_id(service)
if not first_profile_id:
print 'Could not find a valid profile for this user.'
else:
results = get_top_keywords(service, first_profile_id)
print_results(results)
except TypeError, error:
# Handle errors in constructing a query.
print ('There was an error in constructing your query : %s' % error)
except HttpError, error:
# Handle API errors.
print ('Arg, there was an API error : %s : %s' % (error.resp.status, error._get_reason()))
except AccessTokenRefreshError:
# Handle Auth errors.
print ('The credentials have been revoked or expired, please re-run ','the application to re-authorize')
def get_first_profile_id(service):
"""Traverses Management API to return the first profile id.
This first queries the Accounts collection to get the first account ID.
This ID is used to query the Webproperties collection to retrieve the first
webproperty ID. And both account and webproperty IDs are used to query the
Profile collection to get the first profile id.
Args:
service: The service object built by the Google API Python client library.
Returns:
A string with the first profile ID. None if a user does not have any
accounts, webproperties, or profiles.
"""
accounts = service.management().accounts().list().execute()
if accounts.get('items'):
firstAccountId = accounts.get('items')[0].get('id')
webproperties = service.management().webproperties().list(
accountId=firstAccountId).execute()
if webproperties.get('items'):
firstWebpropertyId = webproperties.get('items')[0].get('id')
profiles = service.management().profiles().list(
accountId=firstAccountId,
webPropertyId=firstWebpropertyId).execute()
if profiles.get('items'):
return profiles.get('items')[0].get('id')
return None
def get_top_keywords(service, profile_id):
"""Executes and returns data from the Core Reporting API.
This queries the API for the top 25 organic search terms by visits.
Args:
service: The service object built by the Google API Python client library.
profile_id: String The profile ID from which to retrieve analytics data.
Returns:
The response returned from the Core Reporting API.
"""
return service.data().ga().get(
ids='ga:' + profile_id,
start_date='2012-01-01',
end_date='2012-01-15',
metrics='ga:visits',
dimensions='ga:source,ga:keyword',
sort='-ga:visits',
filters='ga:medium==organic',
start_index='1',
max_results='25').execute()
def print_results(results):
"""Prints out the results.
This prints out the profile name, the column headers, and all the rows of
data.
Args:
results: The response returned from the Core Reporting API.
"""
print
print 'Profile Name: %s' % results.get('profileInfo').get('profileName')
print
# Print header.
output = []
for header in results.get('columnHeaders'):
output.append('%30s' % header.get('name'))
print ''.join(output)
# Print data table.
if results.get('rows', []):
for row in results.get('rows'):
output = []
for cell in row:
output.append('%30s' % cell)
print ''.join(output)
else:
print 'No Rows Found'
if __name__ == '__main__':
main(sys.argv)
according to the error the program doesn't recognize 'file'. In IPython this error comes up (not 100% sure why) but this error shouldn't come up when running a file. In a file the 'file' argument will return the full path and the file name.
Try creating a file and running from there or simply paste in a the full path and file name instead.
Also be sure that the client secrets are located in the same folder as your script!