简体   繁体   中英

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

I have tried uploading file to Google Drive from my local system using a Python script but I keep getting HttpError 403. The script is as follows:

from googleapiclient.http import MediaFileUpload
from googleapiclient import discovery
import httplib2
import auth

SCOPES = "https://www.googleapis.com/auth/drive"
CLIENT_SECRET_FILE = "client_secret.json"
APPLICATION_NAME = "test"
authInst = auth.auth(SCOPES, CLIENT_SECRET_FILE, APPLICATION_NAME)
credentials = authInst.getCredentials()
http = credentials.authorize(httplib2.Http())
drive_serivce = discovery.build('drive', 'v3', credentials=credentials)
file_metadata = {'name': 'gb1.png'}
media = MediaFileUpload('./gb.png',
                        mimetype='image/png')
file = drive_serivce.files().create(body=file_metadata,
                                    media_body=media,
                                    fields='id').execute()
print('File ID: %s' % file.get('id'))

The error is :

googleapiclient.errors.HttpError: <HttpError 403 when requesting
https://www.googleapis.com/upload/drive/v3/files?uploadType=multipart&alt=json&fields=id 
returned "Insufficient Permission: Request had insufficient authentication scopes.">

Am I using the right scope in the code or missing anything ?

I also tried a script I found online and it is working fine but the issue is that it takes a static token, which expires after some time. So how can I refresh the token dynamically?

Here is my code:

import json
import requests
headers = {
    "Authorization": "Bearer TOKEN"}
para = {
    "name": "account.csv",
    "parents": ["FOLDER_ID"]
}
files = {
    'data': ('metadata', json.dumps(para), 'application/json; charset=UTF-8'),
    'file': ('mimeType', open("./test.csv", "rb"))
}
r = requests.post(
    "https://www.googleapis.com/upload/drive/v3/files?uploadType=multipart",
    headers=headers,
    files=files
)
print(r.text)

"Insufficient Permission: Request had insufficient authentication scopes."

Means that the user you have authenticated with has not granted your application permission to do what you are trying to do.

The files.create method requires that you have authenticated the user with one of the following scopes.

在此处输入图片说明

while your code does appear to be using the full on drive scope. What i suspect has happens is that you have authenticated your user then changed the scope in your code and not promoted the user to login again and grant consent. You need to remove the users consent from your app either by having them remove it directly in their google account or just deleteing the credeitnals you have stored in your app. This will force the user to login again.

There is also an approval prompt force option to the google login but am not a python dev so im not exactly sure how to force that. it should be something like the prompt='consent' line below.

flow = OAuth2WebServerFlow(client_id=CLIENT_ID,
                           client_secret=CLIENT_SECRET,
                           scope='https://spreadsheets.google.com/feeds '+
                           'https://docs.google.com/feeds',
                           redirect_uri='http://example.com/auth_return',
                           prompt='consent')

consent screen

If done correctly the user should see a screen like this

在此处输入图片说明

Prompting them to grant you full access to their drive account

Token pickle

If you are following googles tutorial here https://developers.google.com/drive/api/v3/quickstart/python you need to delete the token.pickle that contains the users stored consent.

if os.path.exists('token.pickle'):
    with open('token.pickle', 'rb') as token:
        creds = pickle.load(token)

Answer:

Delete your token.pickle file and re-run your application.

More Information:

As long as you have the correct set of credentials then all that is required when you update the scopes of your application is to re-obtain a token. Delete the token file located in the application's root folder, then run the application again. If you have the https://www.googleapis.com/auth/drive scope, and the Gmail API enabled in the developer console, you should be good.

References:

You can use the google-api-python-client to build a Drive service for using Drive API .

  • Get your Authorization as by following the first 10 steps of this answer .
  • If you want the user to go through consent screen only once, then store the credentials in a file. They include a refresh token that app can use to request authorization after expired . Example

With a valid Drive Service you can upload a file by calling a function like the following upload_file :

def upload_file(drive_service, filename, mimetype, upload_filename, resumable=True, chunksize=262144):
    media = MediaFileUpload(filename, mimetype=mimetype, resumable=resumable, chunksize=chunksize)
    # Add all the writable properties you want the file to have in the body!
    body = {"name": upload_filename} 
    request = drive_service.files().create(body=body, media_body=media).execute()
    if getFileByteSize(filename) > chunksize:
        response = None
        while response is None:
            chunk = request.next_chunk()
            if chunk:
                status, response = chunk
                if status:
                    print("Uploaded %d%%." % int(status.progress() * 100))
    print("Upload Complete!")

Now pass in the parameters and call the function...

# Upload file
upload_file(drive_service, 'my_local_image.png', 'image/png', 'my_imageination.png' )

You will see the file with the name: my_imageination.png in your Google Drive root folder.

More about the Drive API v3 service and available methods here .


getFileSize() function:

def getFileByteSize(filename):
    # Get file size in python
    from os import stat
    file_stats = stat(filename)
    print('File Size in Bytes is {}'.format(file_stats.st_size))
    return file_stats.st_size

Uploading to certain folder(s) in your drive is easy...

Just add the parent folder Id(s) in the body of the request.

Here are the properties of a File . 文件的父母 [] 属性

Example:

request_body = {
  "name": "getting_creative_now.png",
  "parents": ['myFiRsTPaRentFolderId',
              'MyOtherParentId',
              'IcanTgetEnoughParentsId'],
}

To use the scope 'https://www.googleapis.com/auth/drive' you need to submit the google app for verification.

Find the image for scope

So use the scope 'https://www.googleapis.com/auth/drive.file' instead of 'https://www.googleapis.com/auth/drive' to upload files without verification.

Also use SCOPES as list.

ex: SCOPES = ['https://www.googleapis.com/auth/drive.file']

I can successfully upload and download the files to google drive by using the above SCOPE.

I found the solution for uploading a file to google drive. Here it is:

import requests
import json
url = "https://www.googleapis.com/oauth2/v4/token"

        payload = "{\n\"" \
                  "client_id\": \"CLIENT_ID" \
                  "\",\n\"" \
                  "client_secret\": \"CLIENT SECRET" \
                  "\",\n\"" \
                  "refresh_token\": \"REFRESH TOKEN" \
                  "\",\n\"" \
                  "grant_type\": \"refresh_token\"\n" \
                  "}"
        headers = {
            'grant_type': 'authorization_code',
            'Content-Type': 'application/json'
        }

        response = requests.request("POST", url, headers=headers, data=payload)

        res = json.loads(response.text.encode('utf8'))


        headers = {
            "Authorization": "Bearer %s" % res['access_token']
        }
        para = {
            "name": "file_path",
            "parents": "google_drive_folder_id"
        }
        files = {
            'data': ('metadata', json.dumps(para), 'application/json; charset=UTF-8'),
            # 'file': open("./gb.png", "rb")
            'file': ('mimeType', open("file_path", "rb"))
        }
        r = requests.post(
            "https://www.googleapis.com/upload/drive/v3/files?uploadType=multipart",
            headers=headers,
            files=files
        )
        print(r.text)

For generating client id, client secret and refresh token, you can follow the link :- click here

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM