×

Search anything:

Download files from Google Drive using Python

Internship at OpenGenus

Get this book -> Problems on Array: For Interviews and Competitive Programming

Introduction

In this article, you will create a python script to download files from and upload files to Google drive. After you have created the script, you can integrate it with your web applications and APIs to download files from and upload files to Google drive.

Prerequisites

Before you begin this article you will need the following:

  • An environment that can run python
  • Some knowledge of python scripting and simple Object Oriented Programming in python
    Note: I use python3.10.6 and an Ubuntu OS for this project. Python versions >= version 3.8 should work all the same for this article.

Step 1 - Environment Set up

Create a new directory and change it using mkdir your_directory; cd your_directory
For this article, we will need to create and activate a new virtual environment:

python3.10 -m venv your_virtual_environment # Create a virtual environment named .venv
. your_virtual_environment/bin/activate # activate the created virtual environment

You will then install google-api-python-client, google-auth-httplib2, google-auth-oauthlib.
Install them using pip install oogle-api-python-client google-auth-httplib2 google-auth-oauthlib.

Step 2 - Google API Credential

We are now done with the requirements, let's get our credentials from this link (Google cloud). Log in with your preferred account and you should have this page below: 1ststepclound

Enable the Google Drive API by clicking on Enabled APIS AND SERVICES on the top bar circled above. You should get a page where you can search for APIs to enable. Search for Google Drive then click it. After that, you will be directed to a page where you can enable it. Follow the above step keenly and you should see the following results:
2ndstepcloud

(Search and click Google API)

3rdstepcloud

(Click enable and you'll get the above result)

Now navigate back to [Google cloud](https://console.cloud.google.com/apis), then click on **OAuth consent screen** on the left sidebar, and add your app_name and user support email, you can upload an image(app logo) to display in the consent screen if you wish. Move down and save.

Now click on Credentials on the left sidebar, then click on CREATE CREDENTIALS on the top bar. Follow the image displayed below to set up your credentials:
4thstepcloud-2

Click on OAuth Client ID as shown below:
5thstepcloud

Then click on web applications as application type in the drop-down, type in your app name in the app name field, and fill the other input fields with the following as specified in the image below:
6thstepcloud

You will get a pop-up with your credentials and a download button to download credentials.json, click it and download it.
Move the credentials.json file to the directory of your virtual environment.

Step 3 - The Drive class

We are going to create a Drive class that will have two methods download and upload. The download will take file_id and file_name as arguments and return either True or False, depending on the status of our request. If we successfully download, True will be returned else False will be returned. The code is as follows:

import io
import os
import pickle
import shutil
from mimetypes import MimeTypes

import requests
from google.auth.transport.requests import Request
from google_auth_oauthlib.flow import InstalledAppFlow
from googleapiclient.discovery import build
from googleapiclient.http import MediaFileUpload, MediaIoBaseDownload


class Drive:
    SCOPES = ["https://www.googleapis.com/auth/drive"]

    def __init__(self):
        self.creds = None

        if os.path.exists("token.pickle"):
            with open("token.pickle", "rb") as token:
                self.creds = pickle.load(token)
        if not self.creds or not self.creds.valid:
            if self.creds and self.creds.expired and self.creds.refresh_token:
                self.creds.refresh(Request())
            else:
                flow = InstalledAppFlow.from_client_secrets_file(
                    "credentials.json", self.SCOPES
                )
                self.creds = flow.run_local_server(host="127.0.0.1", port=8000)
            with open("token.pickle", "wb") as token:
                pickle.dump(self.creds, token)
        self.service = build("drive", "v3", credentials=self.creds)
        results = (
            self.service.files()
            .list(
                pageSize=100,
                fields="files(id, name)",
            )
            .execute()
        )
        items = results.get("files", [])

        print("Here's a list of files: \n")
        print(*items, sep="\n", end="\n\n")

    def download(self, file_id, file_name):
        request = self.service.files().get_media(fileId=file_id)
        fh = io.BytesIO()

        downloader = MediaIoBaseDownload(fh, request, chunksize=204800)
        done = False

        try:
            while not done:
                status, done = downloader.next_chunk()

            fh.seek(0)

            with open(file_name, "wb") as f:
                shutil.copyfileobj(fh, f)

            print("File Downloaded")
            return True
        except:
            print("Something went wrong.")
            return False

    def upload(self, filepath):
        name = filepath.split("/")[-1]
        mimetype = MimeTypes().guess_type(name)[0]

        file_metadata = {"name": name}

        try:
            media = MediaFileUpload(filepath, mimetype=mimetype)

            file = (
                self.service.files()
                .create(body=file_metadata, media_body=media, fields="id")
                .execute()
            )

            print("File Uploaded.")

        except:
            raise UploadError("Can't Upload File.")

The io library is used for working with various types of I/O(Input/Output) streams ranging from text, binary, and raw io. What we need here is for reading binary io files from Google Drive as used in line 49 of the code above fh = io.BytesIO().
The os is used for working with files and it is used in line 20. The pickle library is used in line 22 to deserialize(converts json types to python types). The shutil library is similar to the os library but its functions are even more high level. It is used in line 61 to copy the content of a file to another. And we imported some google-* libraries to work with the Drive API. A token.pickle file is created every time we run our scripts to get an email selection prompt every time.

Line 17 - 45 tried to check if token.pickle file exists, if it does the contents are assigned to self.creds, and if it doesn't a new one is created and its content assigned to self.creds. The code also checks if the credentials have expired, and if it has a new one is generated.
The code also lists the content of the drive after a successful login(lines 34 - 45). So we can a file id from the listed files.

The upload method uploads a file given the filepath to Google Drive, while the download method download a file given its name, and id from Google Drive.

Download Method

In download method from lines 47 to 67, we get a reference to googleapiclient Resource instance using self.service.files().get_media which returns a media object as a string.

Lines 54 to 70 downloader = MediaIoBaseDownload(fh, request, chunksize=204800), downloads media resources by chunk of 204800 taking input stream and media resource of the object as arguments while taking optional chunk size of 204800 bytes which will default to 1024 * 1024 bytes when not given. We make the download in while loop while handling the error and displaying the proper error message and returning False. And after the while loop, we write the stream to a file using the shutil.copyfileobj(fh, f) from the shutil library.

Upload Method

The upload method spans from lines 72 to 90. In lines 73 and 74 we get the filename from the filepath with the knowledge that it will always be after the last forward slash character in a pathname, accessing the -1 index access the last item after the path has been split with /. And the mime-type of the file is gotten using MimeTypes built-in library.
The upload method's major functionalities depend on MediaFileUpload class from the googleapiclient library. We pass filepath and mime-type to it(media = MediaFileUpload(filepath, mimetype=mimetype)). And if upload fail, we raise UploadError("Can't Upload File.")) from the googleclient library.

Step 4 - The main function

The main function is like an invoker of the Drive API class written above. You should put this below your Drive class code in your scripts. What it does majorly is just creating a Drive instance, taking input 1, 2,3 from the command line. Putting 1 as the command line arguments downloads file, 2 uploads, while 3 exits the code.

def main():
    obj = Drive()
    try:
        action = int(os.sys.argv[1])
    except:
        help = f"USAGE: {os.sys.argv[0]} [1|2|3]\n1 - Download file, 2- Upload File, 3- Exit.\n"
        print(help)
        exit(0)

    if action == 1:
        f_id = input("Enter file id: ")
        f_name = input("Enter file name: ")
        obj.download(f_id, f_name)
    elif action == 2:
        f_path = input("Enter full file path: ")
        obj.upload(f_path)
    else:s
        try:
            os.remove("token.pickle")
        except:
            pass
        finally:
            exit()
    try:
        os.remove("token.pickle")
        exit(0)
    except:
        exit(1)
main()

Below are my inputs and outputs for the scripts.

python your_script.py 1 # downloading

run2
run3

python your_script.py 2 # uploading

run4

python your_script.py 3

run5

Conclusion

In this tutorial we have created, a Google API class, credentials.json file from Google cloud, and created a script to download and upload files to Google Drive. We also ran the code and saw the output.

David Oluwafemi

David Oluwafemi

I love meeting new people. I love to teach others and likewise learn from others. Since learning never ends. So I will learn till the very end. I am proficient in Python, JavaScript, and Shell Script.

Read More

Improved & Reviewed by:


OpenGenus Foundation OpenGenus Foundation
Download files from Google Drive using Python
Share this