Search code examples
pythongoogle-drive-api

How to download a file from Google Drive using Python and the Drive API v3


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.


Solution

  • 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)