izzthedude
izzthedude

Reputation: 23

Problem with downloaded files when downloading them through Google Drive API using Python

So I'm trying to download whatever files are in a folder in my Google Drive into a folder in my computer using Python and Google Drive API. But for some reason the files that are downloaded appears to be corrupted and their sizes are just zero bytes. I tried two different solutions and both of 'em aren't working. Can someone tell me what I'm doing wrong?

from __future__ import print_function
import pickle
from pathlib import Path
import requests
from googleapiclient.discovery import build
from google_auth_oauthlib.flow import InstalledAppFlow
from google.auth.transport.requests import Request
from googleapiclient.http import MediaIoBaseDownload
import io, os

def dl_file(g_drive, folderID):
    folder_path = Path("<folder path>")
    files_obj = g_drive.files()
    files_list = files_obj.list(pageSize=100,
                             fields="nextPageToken, files(name, id, webContentLink, parents)").execute()
    items = files_list['files']
    if not items:
        print('No files found.')
    else:
        for item in items:
            if item['parents'] == [folderID]:
                file_name = item['name']

                #Method 1
                fh = io.BytesIO()
                downloader = MediaIoBaseDownload(fh, files_obj.get_media(fileId=item['id']))
                done = False
                while done is False:
                    status, done = downloader.next_chunk()
                    print("Download %d%%." % int(status.progress() * 100))
                with io.open(f"{folder_path.as_posix()}/{file_name}", 'wb') as f:
                    f.seek(0)
                    f.write(fh.read())

                #Method 2
                url = item['webContentLink']
                r = requests.get(url, stream=True)
                if r.ok:
                    print(f"Saving to '{folder_path.name}/'")
                    with open(f"{folder_path.as_posix()}/{file_name}", 'wb') as f:
                        for chunk in r.iter_content(chunk_size=1024 * 8):
                            if chunk:
                                f.write(chunk)
                                f.flush()
                                os.fsync(f.fileno())
                else:  # HTTP status code 4XX/5XX
                    print("Download failed: status code {}\n{}".format(r.status_code, r.text))

g_drive = build('drive', 'v3', credentials=creds)
dl_file(g_drive, "<folder_ID>")

Upvotes: 2

Views: 581

Answers (1)

Tanaike
Tanaike

Reputation: 201553

I believe your goal as follows.

  • You want to download the files which are not Google Docs in the specific folder on Google Drive.
  • You want to achieve this using python.
  • You have already been able to download the files using Drive API.
    • You tried 2 methods of #Method 1 and #Method 2.
    • #Method 1 uses googleapis.
    • #Method 2 uses requests.

For this, how about this answer?

Modification points:

  • In this modification, I would like to modify #Method 1 using googleapis.
  • When the files are downloaded from the specific folder, I would like to propose to directly retrieve the file list except for Google Docs from the specific folder using the "Files: list" method. In this case, the search query is used.

When these are reflected to your script, it becomes as follows.

Modified script:

Please modify dl_file as follows.

def dl_file(g_drive, folderID):
    folder_path = Path("<folder path>")
    files_obj = g_drive.files()
    files_list = files_obj.list(pageSize=100,
                                q="'" + folderID + "' in parents and not mimeType contains 'application/vnd.google-apps'",
                                fields="nextPageToken, files(name, id, webContentLink, parents)").execute()
    items = files_list['files']
    if not items:
        print('No files found.')
    else:
        for item in items:
            file_name = item['name']
            request = g_drive.files().get_media(fileId=item['id'])
            fh = io.FileIO(folder_path.as_posix() + '/' + file_name, mode='wb')
            downloader = MediaIoBaseDownload(fh, request)
            print('Download of ' + file_name)
            done = False
            while done is False:
                status, done = downloader.next_chunk()
                print('Download %d%%.' % int(status.progress() * 100))
  • When above script is run, the downloaded files are created to the directory of <folder path>.

References:

Upvotes: 1

Related Questions