3

I need to upload an image string (as the one you get from requests.get(url).content) to google drive using the PyDrive package. I checked a similar question but the answer accepted there was to save it in a temporary file on a local drive and then upload that.
However, I cannot do that because of local storage and permission restrictions.
The accepted answer was previously to use SetContentString(image_string.decode('utf-8')) since

SetContentString requires a parameter of type str not bytes.

However the error: UnicodeDecodeError: 'utf-8' codec can't decode byte 0x89 in position 0: invalid start byte came up, as in the comments on that answer.
Is there any way to do this without using a temporary file, using PIL/BytesIO/anything that can convert it to be uploaded correctly as a string or somehow using PIL manipulated as an image and uploaded using SetContentFile()?

A basic example of what I'm trying to do is:

img_content = requests.get('https://i.imgur.com/A5gIh7W.jpeg')
file = drive.CreateFile({...})
file.setContentString(img_content.decode('utf-8'))
file.Upload()
Tanaike
  • 181,128
  • 11
  • 97
  • 165
pu239
  • 707
  • 7
  • 17
  • 1
    Thank you for asking this question! Even after searching for hours, I couldn't find a similar issue anywhere else. – aQwus jargon Jul 17 '21 at 10:41

1 Answers1

2

When I saw the document (Upload and update file content) of pydrive, it says as follows.

Managing file content is as easy as managing file metadata. You can set file content with either SetContentFile(filename) or SetContentString(content) and call Upload() just as you did to upload or update file metadata.

And, I searched about the method for directly uploading the binary data to Google Drive. But, I couldn't find it. From this situation, I thought that there might not be such method. So, in this answer, I would like to propose to upload the binary data using requests module. In this case, the access token is retrieved from the authorization script of pydrive. The sample script is as follows.

Sample script:

from pydrive.auth import GoogleAuth
import io
import json
import requests


url = 'https://i.imgur.com/A5gIh7W.jpeg' # Please set the direct link of the image file.
filename = 'sample file' # Please set the filename on Google Drive.
folder_id = 'root' # Please set the folder ID. The file is put to this folder.

gauth = GoogleAuth()
gauth.LocalWebserverAuth()
metadata = {
    "name": filename,
    "parents": [folder_id]
}
files = {
    'data': ('metadata', json.dumps(metadata), 'application/json'),
    'file': io.BytesIO(requests.get(url).content)
}
r = requests.post(
    "https://www.googleapis.com/upload/drive/v3/files?uploadType=multipart",
    headers={"Authorization": "Bearer " + gauth.credentials.access_token},
    files=files
)
print(r.text)

Note:

  • In this script, it supposes that your URL is the direct link of the image file. Please be careful this.

  • In this case, uploadType=multipart is used. The official document says as follows. Ref

    Use this upload type to quickly transfer a small file (5 MB or less) and metadata that describes the file, in a single request. To perform a multipart upload, refer to Perform a multipart upload.

    • When you want to upload the data of the large size, please use the resumable upload. Ref

References:

Tanaike
  • 181,128
  • 11
  • 97
  • 165