9

I have tried downloading file from Google Drive to my local system using python script but facing a "forbidden" issue while running a Python script. The script is as follows:

import requests

url = "https://www.googleapis.com/drive/v3/files/1wPxpQwvEEOu9whmVVJA9PzGPM2XvZvhj?alt=media&export=download"

querystring = {"alt":"media","export":"download"}

headers = {
    'Authorization': "Bearer TOKEN",

    'Host': "www.googleapis.com",
    'Accept-Encoding': "gzip, deflate",
    'Connection': "keep-alive",
    }

response = requests.request("GET", url, headers=headers, params=querystring)

print(response.url)
#
import wget
import os
from os.path import expanduser


myhome = expanduser("/home/sunarcgautam/Music")
### set working dir
os.chdir(myhome)

url = "https://www.googleapis.com/drive/v3/files/1wPxpQwvEEOu9whmVVJA9PzGPM2XvZvhj?alt=media&export=download"
print('downloading ...')
wget.download(response.url)

In this script, I have got forbidden issue. Am I doing anything wrong in the script?

I have also tried another script that I found on a Google Developer page, which is as follows:

import auth
import httplib2
SCOPES = "https://www.googleapis.com/auth/drive.scripts"
CLIENT_SECRET_FILE = "client_secret.json"
APPLICATION_NAME = "test_Download"
authInst = auth.auth(SCOPES, CLIENT_SECRET_FILE, APPLICATION_NAME)
credentials = authInst.getCredentials()
http = credentials.authorize(httplib2.Http())
drive_serivce = discovery.build('drive', 'v3', http=http)

file_id = '1Af6vN0uXj8_qgqac6f23QSAiKYCTu9cA'
request = drive_serivce.files().export_media(fileId=file_id,
                                             mimeType='application/pdf')
fh = io.BytesIO()
downloader = MediaIoBaseDownload(fh, request)
done = False
while done is False:
    status, done = downloader.next_chunk()
    print ("Download %d%%." % int(status.progress() * 100))

This script gives me a URL mismatch error.

So what should be given for redirect URL in Google console credentials? or any other solution for the issue? Do I have to authorise my Google console app from Google in both the script? If so, what will the process of authorising the app because I haven't found any document regarding that.

Aerials
  • 4,231
  • 1
  • 16
  • 20
Gautam Bothra
  • 565
  • 1
  • 8
  • 23

1 Answers1

22

To make requests to Google APIs the work flow is in essence the following:

  1. Go to developer console, log in if you haven't.
  2. Create a Cloud Platform project.
  3. Enable for your project, the APIs you are interested in using with you projects' apps (for example: Google Drive API).
  4. Create and download OAuth 2.0 Client IDs credentials that will allow your app to gain authorization for using your enabled APIs.
  5. Head over to OAuth consent screen, click on enter image description here and add your scope using the enter image description here button. (scope: https://www.googleapis.com/auth/drive.readonly for you). Choose Internal/External according to your needs, and for now ignore the warnings if any.
  6. To get the valid token for making API request the app will go through the OAuth flow to receive the authorization token. (Since it needs consent)
  7. During the OAuth flow the user will be redirected to your the OAuth consent screen, where it will be asked to approve or deny access to your app's requested scopes.
  8. If consent is given, your app will receive an authorization token.
  9. Pass the token in your request to your authorized API endpoints.[2]
  10. Build a Drive Service to make API requests (You will need the valid token)[1]

NOTE:

The available methods for the Files resource for Drive API v3 are here.

When using the Python Google APIs Client, then you can use export_media() or get_media() as per Google APIs Client for Python documentation


IMPORTANT:

Also, check that the scope you are using, actually allows you to do what you want (Downloading Files from user's Drive) and set it accordingly. ATM you have an incorrect scope for your goal. See OAuth 2.0 API Scopes


Sample Code References:

  1. Building a Drive Service:
import google_auth_oauthlib.flow
from google.auth.transport.requests import Request
from google_auth_oauthlib.flow import InstalledAppFlow
from googleapiclient.discovery import build
 
 
class Auth:
 
    def __init__(self, client_secret_filename, scopes):
        self.client_secret = client_secret_filename
        self.scopes = scopes
        self.flow = google_auth_oauthlib.flow.Flow.from_client_secrets_file(self.client_secret, self.scopes)
        self.flow.redirect_uri = 'http://localhost:8080/'
        self.creds = None
 
    def get_credentials(self):
        flow = InstalledAppFlow.from_client_secrets_file(self.client_secret, self.scopes)
        self.creds = flow.run_local_server(port=8080)
        return self.creds

 
# The scope you app will use. 
# (NEEDS to be among the enabled in your OAuth consent screen)
SCOPES = "https://www.googleapis.com/auth/drive.readonly"
CLIENT_SECRET_FILE = "credentials.json"
 
credentials = Auth(client_secret_filename=CLIENT_SECRET_FILE, scopes=SCOPES).get_credentials()
 
drive_service = build('drive', 'v3', credentials=credentials)
  1. Making the request to export or get a file
request = drive_service.files().export(fileId=file_id, mimeType='application/pdf')

fh = io.BytesIO()
downloader = MediaIoBaseDownload(fh, request)
done = False
while done is False:
    status, done = downloader.next_chunk()
    print("Download %d%%" % int(status.progress() * 100))

# The file has been downloaded into RAM, now save it in a file
fh.seek(0)
with open('your_filename.pdf', 'wb') as f:
    shutil.copyfileobj(fh, f, length=131072)
Community
  • 1
  • 1
Aerials
  • 4,231
  • 1
  • 16
  • 20
  • where will i get that file? Is it in the same folder in which i have my script? if so, i am not able to view that file. – Gautam Bothra Feb 11 '20 at 08:28
  • Yes, that file will be stored where your python script is runs. – Aerials Feb 11 '20 at 08:36
  • But i am not able to open that file. it is giving me fatal error while opening the file. – Gautam Bothra Feb 11 '20 at 08:38
  • I have .png extension. – Gautam Bothra Feb 11 '20 at 09:00
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/207575/discussion-between-gautam-bothra-and-aerials). – Gautam Bothra Feb 11 '20 at 09:03
  • 2
    Have a read at the [Google APIs client for Python documentation](https://developers.google.com/resources/api-libraries/documentation/drive/v3/python/latest/drive_v3.files.html) That's where [`get_media()`](https://developers.google.com/resources/api-libraries/documentation/drive/v3/python/latest/drive_v3.files.html#get_media) is documented. – Aerials Feb 11 '20 at 12:21
  • I have same forbidden issue with uploading file. Here is the link of my question related to upload file issue:- https://stackoverflow.com/questions/60182791/upload-a-google-drive-file-using-python-results-in-insufficient-permission-error Please help me over there. – Gautam Bothra Feb 13 '20 at 12:20
  • For how to upload files using the Python client [follow this answer](https://stackoverflow.com/questions/60182791/how-to-upload-a-file-to-google-drive-using-python-and-the-drive-api-v3/60211997#60211997) – Aerials Feb 13 '20 at 16:38
  • https://developers.google.com/identity/protocols/oauth2/scopes#drive – Eduardo Santana Aug 19 '20 at 12:40
  • FYI for anyone else coming to this, I had to change drive_service.files().export to drive_service.files().get_media and it worked for me. – Vincent Nov 03 '20 at 18:35
  • Thanks for pointing me in the right direction. Export was the api to use – LukeSavefrogs Feb 08 '21 at 09:49
  • @Aerials Any reason why the length needs to be set to 131072 in the copyfileodj function? – Tyler Houssian Jun 14 '22 at 21:11
  • Hi, it doesn't. That's the buffer size I chose. – Aerials Jun 17 '22 at 23:53
  • @Aerials Can the PDF be written to the google drive account instead of where the python script is? – user3422637 Jun 18 '22 at 16:53