上传文件到谷歌驱动器与进度条与python请求

moiiocjp  于 2023-02-06  发布在  Python
关注(0)|答案(3)|浏览(127)

这是我使用google-drive-API上传python请求到google drive的代码。

import sys
import json
import requests
from tqdm import tqdm
import requests_toolbelt
from requests.exceptions import JSONDecodeError

class ProgressBar(tqdm):
    def update_to(self, n: int) -> None:
        self.update(n - self.n)

def upload_file(access_token:str, filename:str, filedirectory:str):

    metadata = {
        "title": filename,
    }

    files = {}
    session = requests.session()

    with open(filedirectory, "rb") as fp:
        files["file"] = fp
        files["data"] = ('metadata', json.dumps(metadata), 'application/json')
        encoder = requests_toolbelt.MultipartEncoder(files)
        with ProgressBar(
            total=encoder.len,
            unit="B",
            unit_scale=True,
            unit_divisor=1024,
            miniters=1,
            file=sys.stdout,
        ) as bar:
            monitor = requests_toolbelt.MultipartEncoderMonitor(
                encoder, lambda monitor: bar.update_to(monitor.bytes_read)
            )

            r = session.post(
                "https://www.googleapis.com/upload/drive/v3/files?uploadType=multipart",
                data=monitor,
                allow_redirects=False,
                headers={"Authorization": "Bearer " + access_token},
            )

    try:
        resp = r.json()
        print(resp)
    except JSONDecodeError:
        sys.exit(r.text)

upload_file("access_token", "test.txt", "test.txt")

当我试图发送文件与数据属性在后请求,然后文件名没有发送,并与文件属性在后请求,然后请求工具带不工作。如何修复此错误?

3ks5zfa0

3ks5zfa01#

我看到你的脚本时,我以为请求头中没有包含内容类型,这种情况下,我认为请求正文直接显示在上传的文件中,我想这可能是造成你目前问题的原因,为了消除这个问题,下面的修改如何?

发件人:

r = session.post(
    url,
    data=monitor,
    allow_redirects=False,
    headers={"Authorization": "Bearer " + access_token},
)

收件人:

r = session.post(
    url,
    data=monitor,
    allow_redirects=False,
    headers={
        "Authorization": "Bearer " + access_token,
        "Content-Type": monitor.content_type,
    },
)
  • 在这种情况下,从metadata = { "title": filename },它假设urlhttps://www.googleapis.com/upload/drive/v2/files?uploadType=multipart,请注意这一点。
  • 当您要使用驱动器API v3时,请将metadata = { "title": filename }修改为metadata = { "name": filename },并使用https://www.googleapis.com/upload/drive/v3/files?uploadType=multipart的端点。
  • 使用Drive API v3上载文件时,将返回值{'kind': 'drive#file', 'id': '###', 'name': 'test.txt', 'mimeType': 'text/plain'}
  • 顺便说一下,当你在测试中出现类似badContent的错误时,请尝试测试以下修改,当multipart/form-data的请求体中文件内容放在文件元数据之前时,似乎出现了错误,我不确定这是否是当前的规范,但我不知道请求体的顺序需要检查。
files = {}
  files["file"] = fp
  files["data"] = ('metadata', json.dumps(metadata), 'application/json')
files = collections.OrderedDict(data=("metadata", json.dumps(metadata), "application/json"), file=fp)

注:

  • 我认为在您的脚本中,可能在file_size = os.path.getsize(filename)处发生错误。请再次确认。
  • 当我通过修改上述修改来测试您的脚本时,我可以确认一个测试文件可以用预期的文件名上传到Google云端硬盘,在这种情况下,我还对它进行了如下修改。
files = collections.OrderedDict(data=("metadata", json.dumps(metadata), "application/json"), file=fp)

参考文献:

zte4gxcn

zte4gxcn2#

元数据需要在post主体中作为json发送。
Python Requests post() Method
可选。要发送到指定url的字典、元组列表、字节或文件对象
可选。要发送到指定url的JSON对象

metadata = {
    "name": filename,
  }

  r = session.post(
            url,
            json=json.dumps(metadata),
            allow_redirects=False,
            headers={"Authorization": "Bearer " + access_token},
        )
aiazj4mn

aiazj4mn3#

未来的读者可以在下面找到一个完整的脚本,其中还包含有关如何访问HTTP身份验证的承载令牌的详细信息。
大部分的功劳归于OP和OP问题的答案。

"""
Goal: For one time upload of a large file (as the GDrive UI hangs up)

Step 1 - Create OAuth 2.0 Client ID + Client Secret 
- by following the "Authentication" part of https://pythonhosted.org/PyDrive/quickstart.html

Step 2 - Get Access Token 
- from the OAuth playground -> https://developers.google.com/oauthplayground/ 
    --> Select Drive API v3 -> www.googleapis.com/auth/drive --> Click on "Authorize APIs" 
    --> Click on "Exchange authorization code for tokens" --> "Copy paste the access token" 
    --> Use it in the script below

Step 3 - Run file as daemon process
- nohup python -u upload_gdrive.py > upload_gdrive.log 2>&1 &
- tail -f upload_gdrive.log
"""

import sys
import json
import requests
from tqdm import tqdm
import requests_toolbelt # pip install requests_toolbelt
from requests.exceptions import JSONDecodeError

import collections

class ProgressBar(tqdm):
    def update_to(self, n: int) -> None:
        self.update(n - self.n)

def upload_file(access_token:str, filename:str, filepath:str):

    metadata = {
        "name": filename,
    }

    files = {}
    session = requests.session()

    with open(filepath, "rb") as fp:
        
        files = collections.OrderedDict(data=("metadata", json.dumps(metadata), "application/json"), file=fp)

        encoder = requests_toolbelt.MultipartEncoder(files)
        with ProgressBar(
            total=encoder.len,
            unit="B",
            unit_scale=True,
            unit_divisor=1024,
            miniters=1,
            file=sys.stdout,
        ) as bar:
            monitor = requests_toolbelt.MultipartEncoderMonitor(
                encoder, lambda monitor: bar.update_to(monitor.bytes_read)
            )

            r = session.post(
                "https://www.googleapis.com/upload/drive/v3/files?uploadType=multipart",
                data=monitor,
                allow_redirects=False,
                headers={
                    "Authorization": "Bearer " + access_token
                    , "Content-Type": monitor.content_type
                    },
            )

    try:
        resp = r.json()
        print(resp)
    except JSONDecodeError:
        sys.exit(r.text)

upload_file("<access_token>"
            , "<upload_filename>", "<path_to_file>")

相关问题