首页 > 编程问答 >如何使用python将大文件上传到Onedrive

如何使用python将大文件上传到Onedrive

时间:2024-07-21 14:13:19浏览次数:5  
标签:python azure onedrive azure-identity msal

import requests
from msal import PublicClientApplication
from dotenv import load_dotenv
import os

# Load environment variables
load_dotenv()

# Configuration from environment variables
CLIENT_ID = os.getenv('CLIENT_ID')
# TENANT_ID is not used since we're using the 'consumers' endpoint
CLIENT_SECRET = os.getenv('CLIENT_SECRET')  # This might not be necessary for public clients
USER_ID = os.getenv('USER_ID')

authority_url = 'https://login.microsoftonline.com/consumers'
scopes = ['Files.ReadWrite.All']  # Scope 'https://graph.microsoft.com/.default' might not be needed

app = PublicClientApplication(CLIENT_ID, authority=authority_url)

# The following is a simplistic approach to illustrate the flow
# You need a URL to redirect the user to for login, including the redirect URI
redirect_uri = 'http://localhost:8000/callback'  # Make sure this matches the redirect URI configured in Azure
url = app.get_authorization_request_url(scopes, redirect_uri=redirect_uri)
print("Please go to this URL and sign-in:", url)

# After sign-in, you will receive a callback to the redirect URI with a code
# This part typically happens on your web server which handles the redirect
code = input("Enter the code you received: ")
result = app.acquire_token_by_authorization_code(code, scopes=scopes, redirect_uri=redirect_uri)

if 'access_token' in result:
    access_token = result['access_token']
else:
    print(result.get('error'))
    print(result.get('error_description'))

def upload_file(access_token, file_path, destination_path):
    headers = {
        'Authorization': 'Bearer ' + access_token,
        'Content-Type': 'application/octet-stream'
    }
    with open(file_path, 'rb') as file_data:
        response = requests.put(
            f'https://graph.microsoft.com/v1.0/users/{USER_ID}/drive/root:/{destination_path}:/content',
            headers=headers,
            data=file_data
        )
    return response.json()

我有一个个人 Microsoft 帐户,此代码使用 microsoft GRAPH API 将我的图像和至少 2GB 的 zip 文件上传到 onedrive。但是,我尝试做的事情却从未获得要上传的访问令牌。我不知道我错过了什么。


提供的代码看起来像是用于将文件上传到 OneDrive 的正确起点,但是在获取访问令牌时遇到问题,这表明身份验证流程中存在问题。让我们一步一步地解决这个问题,并探讨针对大型文件的一些重要改进。

1. 理解身份验证流程

的代码使用的是 OAuth 2.0 授权码流,这对于 Web 应用程序和需要更高安全级别的脚本来说非常适合。以下是工作原理:

a. 请求授权码: 的代码首先会构建一个 URL,并将用户重定向到 Microsoft 身份平台以进行登录。 b. 用户登录并授权: 用户在浏览器中访问该 URL,登录到其 Microsoft 帐户,并授予的应用程序访问其 OneDrive 的权限。 c. 接收授权码: 用户登录并授予权限后,Microsoft 会将其重定向到指定的 redirect_uri ,并在 URL 参数中包含一个 code 。 d. 交换代码以获取访问令牌: 的代码需要接收此 code 并将其与的客户端密钥一起发送到 Microsoft 的令牌端点,以换取访问令牌。

遇到的问题很可能出现在步骤 c 和 d 中,因为无法接收代码。

2. 调试身份验证

  • 验证的 redirect_uri 确保在 Azure 门户中为应用程序注册的 redirect_uri 与代码中使用的 redirect_uri http://localhost:8000/callback )完全匹配。不匹配会导致重定向失败。
  • 检查浏览器控制台: 当被重定向到 Microsoft 登录页面并返回时,请检查浏览器的开发人员工具控制台,以获取可能揭示重定向问题的任何错误消息或警告。
  • 使用 Flask 或 Django 之类的简单 Web 框架: 为的重定向 URI 设置一个简单的 Web 服务器,以处理来自 Microsoft 的回调。这将使能够更可靠地接收和处理授权代码。

    ```python from flask import Flask, request, redirect # ... other imports

    app = Flask( name )

    @app.route('/callback') def handle_callback(): code = request.args.get('code') if code: # Now you have the code, proceed to exchange it for an access token result = app.acquire_token_by_authorization_code(code, scopes=scopes, redirect_uri=redirect_uri) # ... handle the result and proceed with file upload else: return "Error: Authorization code not found in request" return "Authorization successful"

    if name == ' main ': app.run(debug=True, port=8000) ```

3. 处理大型文件上传

对于 2GB 或更大的文件,直接上传整个文件可能会遇到超时或内存问题。OneDrive API 支持分段上传,可以将大文件分解为更小的块进行上传。

以下是使用 requests 库执行分段上传的基本步骤:

  • 创建上传会话: 向 OneDrive API 发送一个请求,以创建一个新的上传会话。这将返回一个上传 URL,将使用该 URL 将文件块上传到该 URL。
  • 将文件分割成块: 将的文件分割成大小相等的块(例如,5MB)。
  • 逐块上传: 使用 requests 库中的 put 方法,将每个块上传到 OneDrive API 提供的上传 URL。确保为每个块请求包含适当的 Content-Range 标头。
  • 完成上传: 上传所有块后,向 OneDrive API 发送一个请求以完成上传会话。

4. 代码改进

以下是对的代码的一些建议改进,以实现分段上传:

import requests
from msal import PublicClientApplication
from dotenv import load_dotenv
import os
import math

# ... (load environment variables and configure app as before) ...

def upload_large_file(access_token, file_path, destination_path, chunk_size=5242880):  # 5MB chunks
    file_size = os.path.getsize(file_path)
    headers = {
        'Authorization': 'Bearer ' + access_token
    }

    # 1. Create upload session
    create_session_url = f'https://graph.microsoft.com/v1.0/users/{USER_ID}/drive/root:/{destination_path}:/createUploadSession'
    response = requests.post(create_session_url, headers=headers)
    response.raise_for_status()  # Check for errors
    upload_url = response.json()['uploadUrl']

    # 2. Upload file in chunks
    with open(file_path, 'rb') as file_data:
        total_chunks = math.ceil(file_size / chunk_size)
        for chunk_num in range(total_chunks):
            start_pos = chunk_num * chunk_size
            end_pos = min((chunk_num + 1) * chunk_size, file_size)
            chunk_data = file_data.read(chunk_size)

            content_range = f'bytes {start_pos}-{end_pos-1}/{file_size}'
            headers['Content-Range'] = content_range
            response = requests.put(upload_url, headers=headers, data=chunk_data)
            response.raise_for_status()  # Check for errors
            print(f'Uploaded chunk {chunk_num+1}/{total_chunks}')

    print("File uploaded successfully!")

# ... (rest of your code, using upload_large_file function) ...

请记住,需要将占位符值(如的客户端 ID、租户 ID 和重定向 URI)替换为自己的值。此外,确保在 Azure 门户中为的应用程序注册了适当的 API 权限( Files.ReadWrite.All )。

标签:python,azure,onedrive,azure-identity,msal
From: 78773194

相关文章