Cannot Read Bigquery table sourced from Google Sheet (Oath / Scope Error) - google-sheets

import pandas as pd
from google.cloud import bigquery
import google.auth
# from google.cloud import bigquery
# Create credentials with Drive & BigQuery API scopes
# Both APIs must be enabled for your project before running this code
credentials, project = google.auth.default(scopes=[
'https://www.googleapis.com/auth/drive',
'https://www.googleapis.com/auth/spreadsheets',
'https://www.googleapis.com/auth/bigquery',
])
client = bigquery.Client(credentials=credentials, project=project)
# Configure the external data source and query job
external_config = bigquery.ExternalConfig('GOOGLE_SHEETS')
# Use a shareable link or grant viewing access to the email address you
# used to authenticate with BigQuery (this example Sheet is public)
sheet_url = (
'https://docs.google.com/spreadsheets'
'/d/1uknEkew2C3nh1JQgrNKjj3Lc45hvYI2EjVCcFRligl4/edit?usp=sharing')
external_config.source_uris = [sheet_url]
external_config.schema = [
bigquery.SchemaField('name', 'STRING'),
bigquery.SchemaField('post_abbr', 'STRING')
]
external_config.options.skip_leading_rows = 1 # optionally skip header row
table_id = 'BambooHRActiveRoster'
job_config = bigquery.QueryJobConfig()
job_config.table_definitions = {table_id: external_config}
# Get Top 10
sql = 'SELECT * FROM workforce.BambooHRActiveRoster LIMIT 10'
query_job = client.query(sql, job_config=job_config) # API request
top10 = list(query_job) # Waits for query to finish
print('There are {} states with names starting with W.'.format(
len(top10)))
The error I get is:
BadRequest: 400 Error while reading table: workforce.BambooHRActiveRoster, error message: Failed to read the spreadsheet. Errors: No OAuth token with Google Drive scope was found.
I can pull data in from a BigQuery table created from CSV upload, but when I have a BigQuery table created from a linked Google Sheet, I continue to receive this error.
I have tried to replicate the sample in Google's documentation (Creating and querying a temporary table):
https://cloud.google.com/bigquery/external-data-drive

You are authenticating as yourself, which is generally fine for BQ if you have the correct permissions. Using tables linked to Google Sheets often requires a service account. Create one (or have your BI/IT team create one), and then you will have to share the underlying Google Sheet with the service account. Finally, you will need to modify your python script to use the service account credentials and not your own.
The quick way around this is to use the BQ interface, select * from the Sheets-linked table, and save the results to a new table, and query that new table directly in your python script. This works well if this is a one-time upload/analysis. If the data in the sheets will be changing consistently and you will need to routinely query the data, this is not a long-term solution.

I solved problem by adding scope object to client.
from google.cloud import bigquery
import google.auth
credentials, project = google.auth.default(scopes=[
'https://www.googleapis.com/auth/drive',
'https://www.googleapis.com/auth/bigquery',
])
CLIENT = bigquery.Client(project='project', credentials=credentials)
https://cloud.google.com/bigquery/external-data-drive

import pandas as pd
from google.oauth2 import service_account
from google.cloud import bigquery
#from oauth2client.service_account import ServiceAccountCredentials
SCOPES = ['https://www.googleapis.com/auth/drive','https://www.googleapis.com/auth/bigquery']
SERVICE_ACCOUNT_FILE = 'mykey.json'
credentials = service_account.Credentials.from_service_account_file(
SERVICE_ACCOUNT_FILE, scopes=SCOPES)
delegated_credentials = credentials.with_subject('myserviceaccountt#domain.iam.gserviceaccount.com')
client = bigquery.Client(credentials=delegated_credentials, project=project)
sql = 'SELECT * FROM `myModel`'
DF = client.query(sql).to_dataframe()

You can try to update your default credentials through the console:
gcloud auth application-default login --scopes=https://www.googleapis.com/auth/userinfo.email,https://www.googleapis.com/auth/drive,https://www.googleapis.com/auth/cloud-platform

Related

Google ads API - REST API

Hope you all are doing well. I am new working with Google ads api. I have to retrieve information regarding keywords i.e how many people searched certain keywords , how many clicks and so on... so I have created a manager account on Google ads and under that I have created client account. In client account I have added keywords under keyword planner and I am getting all information mentioned above but I want to get it through REST API in python.
I have everything needed to access API:
(Developer token
login_customer_id
Client ID
Client Secret
refresh token) I have given this information in the .yaml file. and I assume login_customer_id is the manager account id.
Below is the code to access all the keywords information. here I have given the client_idfrom which I want to access keywords information.
import argparse
import sys
from google.ads.googleads.client import GoogleAdsClient
from google.ads.googleads.errors import GoogleAdsException
def main(client, customer_id):
ga_service = client.get_service("GoogleAdsService")
query = """
SELECT
campaign.id,
campaign.name,
ad_group.id,
ad_group.name,
ad_group_criterion.criterion_id,
ad_group_criterion.keyword.text,
ad_group_criterion.keyword.match_type,
metrics.impressions,
metrics.clicks,
metrics.cost_micros
FROM keyword_view WHERE segments.date DURING LAST_7_DAYS
AND campaign.advertising_channel_type = 'SEARCH'
AND ad_group.status = 'ENABLED'
AND ad_group_criterion.status IN ('ENABLED', 'PAUSED')
ORDER BY metrics.impressions DESC
LIMIT 50"""
# Issues a search request using streaming.
search_request = client.get_type("SearchGoogleAdsStreamRequest")
search_request.customer_id = customer_id
search_request.query = query
response = ga_service.search_stream(search_request)
for batch in response:
for row in batch.results:
campaign = row.campaign
ad_group = row.ad_group
criterion = row.ad_group_criterion
metrics = row.metrics
print(
f'Keyword text "{criterion.keyword.text}" with '
f'match type "{criterion.keyword.match_type.name}" '
f"and ID {criterion.criterion_id} in "
f'ad group "{ad_group.name}" '
f'with ID "{ad_group.id}" '
f'in campaign "{campaign.name}" '
f"with ID {campaign.id} "
f"had {metrics.impressions} impression(s), "
f"{metrics.clicks} click(s), and "
f"{metrics.cost_micros} cost (in micros) during "
"the last 7 days."
)
# [END get_keyword_stats]
if name == "main":
googleads_client=GoogleAdsClient.load_from_storage("C:\Users\AnoshpaBansari\PycharmProjects\GoogleAPI\src\creds\googleads.yaml")
parser = argparse.ArgumentParser(
description=("Retrieves a campaign's negative keywords.")
)
# The following argument(s) should be provided to run the example.
#parser.add_argument(
# "-c",
# "--customer_id",
# type=str,
#required=True,
#help="The Google Ads customer ID.",
#)
#args = parser.parse_args()
try:
main(googleads_client, "----------")
except GoogleAdsException as ex:
print(
f'Request with ID "{ex.request_id}" failed with status '
f'"{ex.error.code().name}" and includes the following errors:'
)
for error in ex.failure.errors:
print(f'\tError with message "{error.message}".')
if error.location:
for field_path_element in error.location.field_path_elements:
print(f"\t\tOn field: {field_path_element.field_name}")
sys.exit(1)
but when I run the code I receive this error. I don't know what I am doing wrong.. Can anyone please help?
enter image description here
You must login in Google Ads Manager accounts, go Tools & Settings > API Center and accept the API terms and conditions.

Scrape from website with all same span name

is it possible to scrape “likes number” and “post number” from this website and import data on google sheet?
Because when i try i get empty data since the span of those data are basically all the same…
thanks for help
Edited:
As you even want to push that data to google sheet and read by back from their I could come up with the below solution you could modify according to your need.
First you need to install gspread library and follow this tutorial https://gspread.readthedocs.io/en/latest/oauth2.html to get the credentials to access the google sheets via api and then follow the below updated code.
Your sheet should be like this:
Code:
import requests
import gspread
headers = {'Accept': 'application/json', 'app-token': '33d57ade8c02dbc5a333db99ff9ae26a'}
gc = gspread.service_account(filename="credentials.json")
sh = gc.open("data")
for rownumber,rowvalues in enumerate(sh.sheet1.get_all_values(),1):
if len(rowvalues)==2:
if rowvalues[1]=='':
cookies = requests.post("https://onlyfans.com/api2/v2/init", headers=headers)
data = requests.get(f"https://onlyfans.com/api2/v2/users/{rowvalues[0]}", headers=headers, cookies=cookies)
if data.status_code == 200:
data = data.json()
sh.sheet1.update_cell(rownumber, 2, data["postsCount"])
else:
print(f"Check : {rowvalues}")
else:
cookies = requests.post("https://onlyfans.com/api2/v2/init", headers=headers)
data = requests.get(f"https://onlyfans.com/api2/v2/users/{rowvalues[0]}", headers=headers, cookies=cookies)
if data.status_code == 200:
data = data.json()
sh.sheet1.update_cell(rownumber, 2, data["postsCount"])
print(f"{rownumber} Processed")
Once you run this code you see will data has been updated in google sheets but before running this script follow the URL provided or else you will end up having errors.
Updated Gsheets:
Old:
Seeing to the network logs of that website I was able to extract your desired data by requests library and some of their API calls you check the data.json() dictionary for other data if required.
Follow the below code.
import requests
headers={'Accept': 'application/json', 'app-token': '33d57ade8c02dbc5a333db99ff9ae26a'}
cookies=requests.post("https://onlyfans.com/api2/v2/init",headers=headers)
data=requests.get("https://onlyfans.com/api2/v2/users/elettra_pink",headers=headers,cookies=cookies)
if data.status_code==200:
data=data.json()
print(f'Posts:{data["postsCount"]}\nPhotosCount:{data["photosCount"]}\nVideosCount:{data["videosCount"]}\nFavoritedCount:{data["favoritedCount"]}\nSubscribersCount:{data["subscribersCount"]}')
Output:
Let me know if you have any questions :)

How to make a flask website that generates dynamic google sheets

I'm helping an organization out and they wish to have a website in which you input some numbers and a Google Sheets link should appear in which the numbers are put into some formula to give a result (i.e if you put in 5, 5, 3; (Num1 + Num2) * num3 it'd show a table in which the first two numbers are added then multiplied by the third:
Num1 Num2 Num2 Result
5 5 3 30
I have searched GitHub and the internet but I cannot seem to find a library that can create a Google Sheet from a website with given data input into a formula. Most stuff I found used the gsheet API and only modified an existing sheet. I found a Python (Flask) library called xlsxwriter and I was wondering if there is any way to convert an .xlsx to an online Google Sheet or if possible to just make a Google Sheet from my website.
(My website is in Flask as of right now but since I literally have no backend. If someone knows of a library that is in another web framework, I am willing to switch.)
Thank you, John D
Maybe I am missing something here but the regular Google Sheets API (which is available for Python) allows you to create blank spreadsheets with a specified title.
spreadsheet = {
'properties': {
'title': title
}
}
spreadsheet = service.spreadsheets().create(body=spreadsheet,
fields='spreadsheetId').execute()
print('Spreadsheet ID: {0}'.format(spreadsheet.get('spreadsheetId')))
https://developers.google.com/sheets/api/guides/create
https://github.com/gsuitedevs/python-samples/blob/master/sheets/snippets/spreadsheet_snippets.py
https://developers.google.com/sheets/api/quickstart/python
Here is a more complete sample based on the Google Quickstarts examples:
from __future__ import print_function
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! Adjust scopes as needed
SCOPES = ['https://www.googleapis.com/auth/spreadsheets']
def main():
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('sheets', 'v4', credentials=creds)
# Call the Sheets API
spreadsheet = {
'properties': {
'title': 'New Test Sheet 2'
}
}
spreadsheet = service.spreadsheets().create(body=spreadsheet,
fields='spreadsheetId').execute()
#print('Spreadsheet ID: {0}'.format(spreadsheet.get('spreadsheetId')))
spreadsheet_id = spreadsheet.get('spreadsheetId')
range_name = 'Sheet1!A1:D5'
body = {
"majorDimension": "ROWS",
"values": [
["Item", "Cost", "Stocked", "Ship Date"],
["Wheel", "$20.50", "4", "3/1/2016"], # new row
["Door", "$15", "2", "3/15/2016"],
["Engine", "$100", "1", "30/20/2016"],
["Totals", "=SUM(B2:B4)", "=SUM(C2:C4)", "=MAX(D2:D4)"]
],
}
result = service.spreadsheets().values().update(
spreadsheetId=spreadsheet_id,
range=range_name,
body=body,
valueInputOption='USER_ENTERED'
).execute()
print(result)
if __name__ == '__main__':
main()

How to get content owner info for particular video via YouTube Partner API?

Is there a way to get content owner information (attribution) for particular video via YouTube Partner API?
For example, this video: http://www.youtube.com/watch?v=I67cgXr6L6o&feature=c4-overview&list=UUGnjeahCJW1AF34HBmQTJ-Q is attributed to VEVO.
Is there a way to get that info somehow via API?
It's possbible now:
https://developers.google.com/youtube/partner/docs/v1/ownership/
[EDIT]
I've used this sample to create the snipped below and succesfully got the assets content owner.
You will need setup your python enviromment and the clients_secrets.file correctly
#!/usr/bin/python
import httplib2
import os
import sys
import logging
import requests
import json
import time
from apiclient.discovery import build
from oauth2client.file import Storage
from oauth2client.client import flow_from_clientsecrets
from oauth2client.tools import argparser, run_flow
from symbol import for_stmt
# 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 Developers Console at
# https://console.developers.google.com/.
# 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 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 Developers 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))
YOUTUBE_SCOPES = (
# This OAuth 2.0 access scope allows for read-only access to the authenticated
# user's account, but not other types of account access.
"https://www.googleapis.com/auth/youtube.readonly",
# This OAuth 2.0 scope grants access to YouTube Content ID API functionality.
"https://www.googleapis.com/auth/youtubepartner")
YOUTUBE_API_SERVICE_NAME = "youtube"
YOUTUBE_API_VERSION = "v3"
YOUTUBE_PARTNER_API_SERVICE_NAME = "youtubePartner"
YOUTUBE_PARTNER_API_VERSION = "v1"
KEY = "USE YOUR KEY"
# Authorize the request and store authorization credentials.
def get_authenticated_services(args):
flow = flow_from_clientsecrets(CLIENT_SECRETS_FILE, scope=" ".join(YOUTUBE_SCOPES), 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)
youtube = build(YOUTUBE_API_SERVICE_NAME, YOUTUBE_API_VERSION, http=credentials.authorize(httplib2.Http()))
youtube_partner = build(YOUTUBE_PARTNER_API_SERVICE_NAME, YOUTUBE_PARTNER_API_VERSION, http=credentials.authorize(httplib2.Http()))
return (youtube, youtube_partner)
def get_content_owner_id(youtube_partner):
content_owners_list_response = youtube_partner.contentOwners().list(fetchMine=True).execute()
return content_owners_list_response["items"][0]["id"]
#def
def claim_search(youtube_partner, content_owner_id, _videoId):
video_info = get_video_info(_videoId)
print '\n---------- CLAIM SEARCH LIST - VIDEO (',video_info['title'],') ID: (',_videoId,')'
claims = youtube_partner.claimSearch().list( videoId=_videoId, onBehalfOfContentOwner=content_owner_id).execute()
print ' --- CLAIMS: ',claims
if claims['pageInfo']['totalResults'] < 1:
print " --- DOESN'T HAVE CLAIMS"
return
assetId = claims['items'][0]['assetId']
print ' --- ASSET ID: ', assetId
ownershipHistory = youtube_partner.ownershipHistory().list(assetId=assetId, onBehalfOfContentOwner=content_owner_id).execute()
print ' --- OWNERSHIP HISTORY: ', ownershipHistory
contentOwnerId = ownershipHistory['items'][0]['origination']['owner']
print ' --- CONTENT OWNER ID: ', contentOwnerId
contentOwners = youtube_partner.contentOwners().get(contentOwnerId=contentOwnerId, onBehalfOfContentOwner=content_owner_id).execute()
print ' --- CONTENT OWNERS: ', contentOwners
def get_video_info(videoId):
r = requests.get("https://www.googleapis.com/youtube/v3/videos?id="+videoId+"&part=id,snippet,contentDetails,status,statistics,topicDetails,recordingDetails&key="+KEY)
content = r.content
content = json.loads(content)
return content['items'][0]['snippet']
if __name__ == "__main__":
args = argparser.parse_args()
(youtube, youtube_partner) = get_authenticated_services(args)
#video id's. Ex: "https://www.youtube.com/watch?v=lgSLz5FeXUg"
videos = ['I67cgXr6L6o', 'lgSLz5FeXUg']
content_owner_id = get_content_owner_id(youtube_partner)
for vid in videos :
claim_search(youtube_partner, content_owner_id, vid)
time.sleep(0.5)
The (censored) proof :
There is no way to check other people's ownership or management rights on a video or channel. YouTube deliberately avoids that.
While ownershipHistory works, I saw GET https://www.googleapis.com/youtube/partner/v1/assets?id=[multiple asset ids] also worked when it's called with fetchOwnership=effective option
https://developers.google.com/youtube/partner/docs/v1/assets/list

Files uploaded using Oauth 2.0 service account do not appear

Trying to use Oauth 2.0 server to server authentication (using a service account) to upload a file to google drive. Have used their sample code as a reference, the resulting script is something like this:
import httplib2
import pprint
import sys
from apiclient.discovery import build
from oauth2client.client import SignedJwtAssertionCredentials
from apiclient.http import MediaFileUpload
def main(argv):
# Load the key in PKCS 12 format that you downloaded from the Google API
# Console when you created your Service account.
f = open('key.p12', 'rb')
key = f.read()
f.close()
# Check https://developers.google.com/drive/scopes for all available scopes
OAUTH_SCOPE = 'https://www.googleapis.com/auth/drive'
# Path to the file to upload
FILENAME = 'testfile.txt'
# Create an httplib2.Http object to handle our HTTP requests and authorize it
# with the Credentials. Note that the first parameter, service_account_name,
# is the Email address created for the Service account. It must be the email
# address associated with the key that was created.
credentials = SignedJwtAssertionCredentials(
'xxxxx-xxxxxxx#developer.gserviceaccount.com',
key,
OAUTH_SCOPE)
http = httplib2.Http()
http = credentials.authorize(http)
drive_service = build('drive', 'v2', http=http)
# Insert a file
media_body = MediaFileUpload(FILENAME, mimetype='text/plain', resumable=True)
body = {
'title': 'My document',
'description': 'A test document',
'mimeType': 'text/plain'
}
fil = drive_service.files().insert(body=body, media_body=media_body).execute()
pprint.pprint(fil)
if __name__ == '__main__':
main(sys.argv)
The script seems to run ok (no errors, pprint shows output that seems to be fine). However the google drive page for the account does not show the uploaded file. When trying to access one of the links from the pprint output to see the file I get a "You need permission" message from Google Drive, which is weird, as I am logged to the account in which I created the service account.
The file is owned by the service account, not your Google account. Service accounts have their own 5gb of space for Google Drive.
You'll need to either share the file with your user account or have the service account impersonate your user account (assuming you're in a Google Apps domain) so that the file is created and owned by your user account.

Resources