问题
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)
回答1:
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:
- Google Drive API - Files: create method
回答2:
"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)
回答3:
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'],
}
来源:https://stackoverflow.com/questions/60182791/how-to-upload-a-file-to-google-drive-using-python-and-the-drive-api-v3