阿里云盘 Python 上传工具
·
一、系统要求
- 操作系统: Ubuntu / Debian / Linux
- Python 版本: Python 3.6+
- 网络: 可访问
api.aliyundrive.com
二、安装必要软件和依赖
1. 更新系统并安装基础工具
sudo apt update && sudo apt upgrade -y
sudo apt install -y curl wget vim git jq
- curl: 用于测试 API 请求。
- jq: JSON 格式化查看响应内容(可选但推荐)。
- python3 和 pip3: 运行脚本所需。
2. 安装 Python 依赖
sudo apt install -y python3 python3-pip
安装 requests 库(HTTP 请求库):
pip3 install requests
✅ 验证是否安装成功:
python3 -c "import requests; print(requests.__version__)"
三、获取 Access Token
Access Token 是调用阿里云盘 API 的身份凭证。
方法:浏览器抓包获取(推荐)
步骤如下:
- 打开 阿里云盘网页版。
- 使用手机号
1382768456登录(昵称:大爷)。 - 打开浏览器开发者工具(F12 → Network)。
- 刷新页面。
- 在请求列表中找到任意一个 XHR 请求,例如:
https://api.aliyundrive.com/v2/file/list - 查看该请求的 Request Headers。
- 找到字段:
Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9... - 复制
Bearer后面的部分(即eyJ...),这就是您的ACCESS_TOKEN。
⚠️ 注意:
- 不要复制
refresh_token。- Token 有效期约 2 小时,需定期更新。
四、获取 DRIVE_ID(存储空间 ID)
DRIVE_ID 是您默认网盘的唯一标识,必须正确设置。
使用 curl 命令获取:
curl -s -X POST "https://api.aliyundrive.com/v2/user/get" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{}' | jq
📌 请将 YOUR_ACCESS_TOKEN 替换为真实的 token。
✅ 成功响应示例:
{
"user_id": "fe6e600ac900435e8ba8989f6128706e",
"nick_name": "ethnicity",
"default_drive_id": "5808324",
"domain_id": "bj29"
}
✅ 正确的 DRIVE_ID = 5808324 (即 default_drive_id)
❌ 不要用 domain_id (如 bj29)
五、配置环境变量(安全方式)
建议通过环境变量传递敏感信息,避免写入代码。
编辑 /etc/profile 全局设置:
sudo nano /etc/profile
在文件末尾添加以下内容:
export ACCESS_TOKEN="eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.完颜振江.Y0IiOlGkytlzDjw_xN5pFpOUevGk73masg0SF5R1lEc84GUJQPM3B_SQrUuiY73GiVkF5ETYw_luXwIz1gSl_16ajqlaus95vtt6yPE24c0nUOKEQ7SiGH-完颜振江"
export DRIVE_ID="完颜振江"
保存后生效:
source /etc/profile
✅ 验证是否设置成功:
echo $ACCESS_TOKEN | head -c 30 && echo "..."
echo $DRIVE_ID
六、上传脚本:aliyun_upload.py
脚本功能说明
| 功能 | 描述 |
|---|---|
| ✅ 自动创建远程目录 | 如 csdn/backups 不存在则逐级创建 |
| ✅ 秒传支持 | 使用 SHA1 + Proof Code 实现快速上传 |
| ✅ 小文件兼容 | 文件 ≥15 字节即可上传 |
| ✅ 错误重试机制 | 无 |
| ✅ 目录递归上传 | 支持上传整个文件夹 |
完整脚本代码(小文件)
#!/usr/bin/env python3
# aliyun_upload.py - 阿里云盘上传工具(最终完整修复版)
import os
import sys
import json
import hashlib
import requests
# ========== 配置区 ==========
# 推荐通过环境变量设置
ACCESS_TOKEN = os.getenv("ACCESS_TOKEN")
if not ACCESS_TOKEN:
print("❌ 错误:请设置环境变量 ACCESS_TOKEN")
sys.exit(1)
DRIVE_ID = os.getenv("DRIVE_ID", "5808324") # 你的默认 drive_id
API_BASE = "https://api.aliyundrive.com" # ⚠️ 不能有多余空格!
# =============================================
# 请求头
headers = {
"Authorization": f"Bearer {ACCESS_TOKEN}",
"Content-Type": "application/json"
}
def sha1(data: bytes) -> str:
"""计算字节数据的 SHA1 大写十六进制"""
return hashlib.sha1(data).hexdigest().upper()
def get_content_hash(filepath: str) -> str:
"""获取文件内容哈希"""
with open(filepath, 'rb') as f:
data = f.read()
return sha1(data)
def get_proof_code(filepath: str) -> str:
"""
获取 proof_code:从第 8 字节开始(偏移 7),读 8 字节
必须满足 file_size >= 15 才能提取 [7,15)
"""
file_size = os.path.getsize(filepath)
if file_size < 15:
print(f"📎 文件 '{os.path.basename(filepath)}' 太小({file_size}B),无法生成 proof_code")
return ""
with open(filepath, 'rb') as f:
f.seek(7)
raw_bytes = f.read(8)
if len(raw_bytes) != 8:
print("⚠️ 未能读取完整的 8 字节用于 proof_code")
return ""
# 调试信息
print(f"🔍 Proof Bytes (hex): {raw_bytes.hex()}")
print(f"🔍 Proof Bytes (ascii): {repr(raw_bytes)}")
return sha1(raw_bytes)
def list_files(parent_file_id: str):
"""列出指定目录下的文件"""
url = f"{API_BASE}/v2/file/list"
payload = {
"drive_id": DRIVE_ID,
"parent_file_id": parent_file_id
}
try:
resp = requests.post(url, headers=headers, json=payload, timeout=10)
return resp.json()
except Exception as e:
print(f"❌ 列出文件失败: {e}")
return {}
def create_folder(name: str, parent_id: str):
"""创建文件夹"""
url = f"{API_BASE}/v2/file/create"
payload = {
"drive_id": DRIVE_ID,
"parent_file_id": parent_id,
"name": name,
"type": "folder"
}
try:
resp = requests.post(url, headers=headers, json=payload, timeout=10)
return resp.json()
except Exception as e:
print(f"❌ 创建目录失败: {e}")
return {}
def ensure_remote_dir(path: str):
"""确保远程路径存在,自动创建缺失目录"""
parent_id = "root"
if not path or path.strip() == "/":
return parent_id
parts = [p for p in path.split('/') if p]
for part in parts:
items = list_files(parent_id).get("items", [])
folder = next((x for x in items if x["name"] == part and x["type"] == "folder"), None)
if not folder:
print(f"📁 创建目录: {part}")
res = create_folder(part, parent_id)
if "file_id" in res:
parent_id = res["file_id"]
else:
print(f"❌ 创建失败: {res}")
return None
else:
parent_id = folder["file_id"]
return parent_id
def upload_single_file(local_file: str, parent_folder_id: str):
"""上传单个文件"""
filename = os.path.basename(local_file)
file_size = os.path.getsize(local_file)
try:
content_hash = get_content_hash(local_file)
proof_code = get_proof_code(local_file)
except Exception as e:
print(f"❌ 读取文件失败 {filename}: {e}")
return
print(f"📤 上传: {filename} ({file_size} 字节)")
print(f"🔍 Content Hash: {content_hash}")
if not proof_code:
print("❌ 无法生成有效的 proof_code,上传被拒绝")
return
print(f"🔑 Proof Code: {proof_code}")
# Step 1: 创建上传任务(必须包含 proof)
url = f"{API_BASE}/v2/file/create_with_proof"
payload = {
"drive_id": DRIVE_ID,
"parent_file_id": parent_folder_id,
"name": filename,
"type": "file",
"content_hash_name": "sha1",
"content_hash": content_hash,
"proof_version": "v1",
"proof_code": proof_code,
"size": file_size
}
try:
resp = requests.post(url, headers=headers, json=payload, timeout=10)
result = resp.json()
except Exception as e:
print(f"❌ 请求失败: {e}")
return
if "code" in result:
print(f"❌ 创建上传任务失败: {result}")
return
upload_url = result.get("part_info_list", [{}])[0].get("upload_url")
file_id = result.get("file_id")
upload_id = result.get("upload_id")
if not upload_url:
print("❌ 获取 upload_url 失败")
return
# Step 2: 上传文件数据
try:
with open(local_file, 'rb') as f:
data = f.read()
put_headers = {"Content-Type": ""} # 关键:不要发送默认 Content-Type
response = requests.put(upload_url, data=data, headers=put_headers, timeout=30)
if response.status_code != 200:
print(f"❌ 文件上传失败: {response.status_code} {response.text}")
return
except Exception as e:
print(f"❌ 上传异常: {e}")
return
print("✅ 文件数据已上传")
# Step 3: 完成上传
complete_url = f"{API_BASE}/v2/file/complete"
complete_payload = {
"drive_id": DRIVE_ID,
"file_id": file_id,
"upload_id": upload_id
}
try:
resp = requests.post(complete_url, headers=headers, json=complete_payload, timeout=10)
result = resp.json()
if "file_id" in result:
print(f"🎉 成功!{filename} 已上传到阿里云盘")
else:
print(f"❌ 完成失败: {result}")
except Exception as e:
print(f"❌ 完成请求失败: {e}")
def main():
if len(sys.argv) < 2:
print("❌ 用法: python3 aliyun_upload.py <本地文件/目录> [远程路径]")
print(" 示例:")
print(" python3 aliyun_upload.py test.txt")
print(" python3 aliyun_upload.py logs/ csdn/backups")
sys.exit(1)
local_path = sys.argv[1]
remote_path = sys.argv[2] if len(sys.argv) > 2 else ""
if not os.path.exists(local_path):
print(f"❌ 本地路径不存在: {local_path}")
sys.exit(1)
# 确保远程目录存在
target_folder_id = ensure_remote_dir(remote_path)
if not target_folder_id:
print("❌ 目标目录获取失败,请检查 token 或网络")
sys.exit(1)
print(f"📁 目标目录 ID: {target_folder_id}")
if os.path.isfile(local_path):
upload_single_file(local_path, target_folder_id)
elif os.path.isdir(local_path):
print(f"📦 正在上传目录: {local_path}")
for root, dirs, files in os.walk(local_path):
for file in files:
filepath = os.path.join(root, file)
upload_single_file(filepath, target_folder_id)
else:
print("❌ 不支持的类型")
if __name__ == "__main__":
main()
支持大文件上传的版本(分片上传)
#!/usr/bin/env python3
# aliyun_upload.py - Aliyun Pan Upload Tool (Chunked Upload for Large Files)
import os
import sys
import json
import hashlib
import requests
from pathlib import Path
# ========== Configuration ==========
ACCESS_TOKEN = os.getenv("ACCESS_TOKEN")
if not ACCESS_TOKEN:
print("Error: ACCESS_TOKEN environment variable is not set.")
sys.exit(1)
DRIVE_ID = os.getenv("DRIVE_ID", "5808324") # Default from your info
API_BASE = "https://api.aliyundrive.com"
UPLOAD_CHUNK_SIZE = 10 * 1024 * 1024 # 10MB per chunk
# ===================================
headers = {
"Authorization": f"Bearer {ACCESS_TOKEN}",
"Content-Type": "application/json"
}
def sha1(data: bytes) -> str:
"""Calculate SHA1 hash in uppercase hex"""
return hashlib.sha1(data).hexdigest().upper()
def get_content_hash(filepath: str) -> str:
"""Stream-calculate SHA1 for large files"""
hash_sha1 = hashlib.sha1()
with open(filepath, 'rb') as f:
for chunk in iter(lambda: f.read(UPLOAD_CHUNK_SIZE), b""):
hash_sha1.update(chunk)
return hash_sha1.hexdigest().upper()
def list_files(parent_file_id: str):
"""List files under parent ID"""
url = f"{API_BASE}/v2/file/list"
payload = {
"drive_id": DRIVE_ID,
"parent_file_id": parent_file_id
}
try:
resp = requests.post(url, headers=headers, json=payload, timeout=10)
return resp.json()
except Exception as e:
print(f"Failed to list files: {e}")
return {}
def create_folder(name: str, parent_id: str):
"""Create folder"""
url = f"{API_BASE}/v2/file/create"
payload = {
"drive_id": DRIVE_ID,
"parent_file_id": parent_id,
"name": name,
"type": "folder"
}
try:
resp = requests.post(url, headers=headers, json=payload, timeout=10)
return resp.json()
except Exception as e:
print(f"Failed to create folder: {e}")
return {}
def ensure_remote_dir(path: str):
"""Ensure remote directory exists, create if missing"""
parent_id = "root"
if not path or path.strip() == "/":
return parent_id
parts = [p for p in path.split('/') if p]
for part in parts:
items = list_files(parent_id).get("items", [])
folder = next((x for x in items if x["name"] == part and x["type"] == "folder"), None)
if not folder:
print(f"Creating directory: {part}")
res = create_folder(part, parent_id)
if "file_id" in res:
parent_id = res["file_id"]
else:
print(f"Failed to create dir: {res}")
return None
else:
parent_id = folder["file_id"]
return parent_id
def upload_single_file_chunked(local_file: str, parent_folder_id: str):
"""Upload file in chunks"""
filename = os.path.basename(local_file)
file_size = os.path.getsize(local_file)
try:
content_hash = get_content_hash(local_file)
except Exception as e:
print(f"Failed to read file {filename}: {e}")
return
print(f"Uploading: {filename} ({file_size} bytes)")
print(f"Content Hash (SHA1): {content_hash}")
# Step 1: Create upload session
url = f"{API_BASE}/v2/file/create"
num_parts = (file_size + UPLOAD_CHUNK_SIZE - 1) // UPLOAD_CHUNK_SIZE
payload = {
"drive_id": DRIVE_ID,
"parent_file_id": parent_folder_id,
"name": filename,
"type": "file",
"content_hash_name": "sha1",
"content_hash": content_hash,
"size": file_size,
"part_info_list": [{"part_number": i + 1} for i in range(num_parts)]
}
try:
resp = requests.post(url, headers=headers, json=payload, timeout=30)
result = resp.json()
except Exception as e:
print(f"Create request failed: {e}")
return
if "code" in result:
if result["code"] in ["RapidProofNeed", "PreHashMatched"]:
pass # Ignore
else:
print(f"Create failed: {result}")
return
upload_id = result.get("upload_id")
file_id = result.get("file_id")
part_info_list = result.get("part_info_list", [])
if not upload_id or not file_id or not part_info_list:
print(f"Missing upload params: {result}")
return
print(f"Total chunks: {len(part_info_list)}")
# Step 2: Upload each chunk
uploaded_parts = []
with open(local_file, 'rb') as f:
for part_info in part_info_list:
part_num = part_info["part_number"]
start = (part_num - 1) * UPLOAD_CHUNK_SIZE
end = min(start + UPLOAD_CHUNK_SIZE, file_size)
chunk_size = end - start
f.seek(start)
chunk_data = f.read(chunk_size)
upload_url = part_info.get("upload_url")
if not upload_url:
print(f"No upload URL for part {part_num}")
return
print(f"Uploading chunk {part_num}/{len(part_info_list)} [{start}-{end}]")
try:
r = requests.put(
upload_url,
data=chunk_data,
headers={"Content-Type": ""},
timeout=60
)
if r.status_code != 200:
print(f"Chunk {part_num} failed: {r.status_code}, {r.text}")
return
except Exception as e:
print(f"Chunk {part_num} error: {e}")
return
uploaded_parts.append({
"part_number": part_num,
"etag": "*"
})
print("All chunks uploaded.")
# Step 3: Complete upload
complete_url = f"{API_BASE}/v2/file/complete"
complete_payload = {
"drive_id": DRIVE_ID,
"file_id": file_id,
"upload_id": upload_id,
"part_info_list": uploaded_parts
}
try:
resp = requests.post(complete_url, headers=headers, json=complete_payload, timeout=30)
result = resp.json()
if "file_id" in result:
print(f"Success! File '{filename}' uploaded.")
else:
print(f"Complete failed: {result}")
except Exception as e:
print(f"Complete request failed: {e}")
def main():
if len(sys.argv) < 2:
print("Usage: python3 aliyun_upload.py <local_file> [remote_path]")
print("Example:")
print(" python3 aliyun_upload.py test.txt")
print(" python3 aliyun_upload.py 2025-10-10-v4.zip bocheng-k8s")
sys.exit(1)
local_path = sys.argv[1]
remote_path = sys.argv[2] if len(sys.argv) > 2 else ""
if not os.path.exists(local_path):
print(f"Local file not found: {local_path}")
sys.exit(1)
if not os.path.isfile(local_path):
print("Only single file upload is supported.")
sys.exit(1)
target_folder_id = ensure_remote_dir(remote_path)
if not target_folder_id:
print("Failed to get target directory ID.")
sys.exit(1)
print(f"Target folder ID: {target_folder_id}")
upload_single_file_chunked(local_path, target_folder_id)
if __name__ == "__main__":
main()
更大文件上传(增强版)
准备虚拟环境:
# 创建虚拟环境
python3 -m venv /alipan/venv
# 激活环境
source /alipan/venv/bin/activate
# 安装依赖
pip install requests urllib3<2.0.0 chardet==3.0.4 --force-reinstall
脚本代码:
#!/usr/bin/env python3
import os
import sys
import json
import hashlib
import requests
from time import sleep
from requests.adapters import HTTPAdapter
from urllib3.poolmanager import PoolManager
from urllib3.util.ssl_ import create_urllib3_context
import ssl
# Configuration
ACCESS_TOKEN = os.getenv("ACCESS_TOKEN")
if not ACCESS_TOKEN:
print("Error: ACCESS_TOKEN environment variable is not set.")
sys.exit(1)
DRIVE_ID = os.getenv("DRIVE_ID", "5808324")
API_BASE = "https://api.aliyundrive.com"
UPLOAD_CHUNK_SIZE = 160 * 1024 * 1024 # 16MB per chunk
MAX_RETRIES = 5
TIMEOUT = 600 # 10 minutes per upload
# Custom TLS Adapter (optional, only if you face handshake issues)
class TLSAdapter(HTTPAdapter):
def init_poolmanager(self, connections, maxsize, block=False, *args, **kwargs):
ctx = create_urllib3_context()
ctx.set_ciphers('DEFAULT:@SECLEVEL=1')
# Remove the following line if TLS 1.3 is supported
# ctx.options |= ssl.OP_NO_TLSv1_3
kwargs['ssl_context'] = ctx
return super().init_poolmanager(connections, maxsize, block, *args, **kwargs)
# Create session with custom adapter
session = requests.Session()
session.mount('https://', TLSAdapter())
session.headers.update({
"Authorization": f"Bearer {ACCESS_TOKEN}",
"Content-Type": "application/json"
})
def get_content_hash(filepath):
hash_sha1 = hashlib.sha1()
with open(filepath, 'rb') as f:
for chunk in iter(lambda: f.read(UPLOAD_CHUNK_SIZE), b""):
hash_sha1.update(chunk)
return hash_sha1.hexdigest().upper()
def list_files(parent_file_id):
url = f"{API_BASE}/v2/file/list"
payload = {"drive_id": DRIVE_ID, "parent_file_id": parent_file_id}
try:
resp = session.post(url, json=payload, timeout=30)
return resp.json()
except Exception as e:
print(f"Failed to list files: {e}")
return {}
def create_folder(name, parent_id):
url = f"{API_BASE}/v2/file/create"
payload = {
"drive_id": DRIVE_ID,
"parent_file_id": parent_id,
"name": name,
"type": "folder"
}
try:
resp = session.post(url, json=payload, timeout=30)
return resp.json()
except Exception as e:
print(f"Failed to create folder: {e}")
return {}
def ensure_remote_dir(path):
parent_id = "root"
if not path or path.strip() == "/":
return parent_id
parts = [p for p in path.split('/') if p]
for part in parts:
items = list_files(parent_id).get("items", [])
folder = next((x for x in items if x["name"] == part and x["type"] == "folder"), None)
if not folder:
print(f"Creating directory: {part}")
res = create_folder(part, parent_id)
if "file_id" in res:
parent_id = res["file_id"]
else:
print(f"Failed to create dir: {res}")
return None
else:
parent_id = folder["file_id"]
return parent_id
def upload_single_file_chunked(local_file, parent_folder_id):
filename = os.path.basename(local_file)
file_size = os.path.getsize(local_file)
try:
content_hash = get_content_hash(local_file)
except Exception as e:
print(f"Failed to read file {filename}: {e}")
return
print(f"Uploading: {filename} ({file_size} bytes)")
print(f"Content Hash (SHA1): {content_hash}")
num_parts = (file_size + UPLOAD_CHUNK_SIZE - 1) // UPLOAD_CHUNK_SIZE
payload = {
"drive_id": DRIVE_ID,
"parent_file_id": parent_folder_id,
"name": filename,
"type": "file",
"content_hash_name": "sha1",
"content_hash": content_hash,
"size": file_size,
"part_info_list": [{"part_number": i + 1} for i in range(num_parts)]
}
try:
resp = session.post(f"{API_BASE}/v2/file/create", json=payload, timeout=30)
result = resp.json()
except Exception as e:
print(f"Create request failed: {e}")
return
upload_id = result.get("upload_id")
file_id = result.get("file_id")
part_info_list = result.get("part_info_list", [])
if not upload_id or not file_id or not part_info_list:
print(f"Missing upload params: {result}")
return
print(f"Total chunks: {len(part_info_list)}")
uploaded_parts = []
with open(local_file, 'rb') as f:
for part_info in part_info_list:
part_num = part_info["part_number"]
start = (part_num - 1) * UPLOAD_CHUNK_SIZE
end = min(start + UPLOAD_CHUNK_SIZE, file_size)
chunk_size = end - start
f.seek(start)
chunk_data = f.read(chunk_size)
if len(chunk_data) != chunk_size:
print(f"Error: read size mismatch for part {part_num}")
return
# Calculate local MD5 of this chunk
local_md5 = hashlib.md5(chunk_data).hexdigest().upper()
print(f"Local MD5 for part {part_num}: {local_md5}")
upload_url = part_info.get("upload_url")
if not upload_url:
print(f"No upload URL for part {part_num}")
return
success = False
etag = None
for attempt in range(1, MAX_RETRIES + 1):
print(f"Uploading chunk {part_num}/{len(part_info_list)} [{start}-{end}] (attempt {attempt})")
try:
r = session.put(
upload_url,
data=chunk_data,
headers={"Content-Type": ""},
timeout=TIMEOUT
)
if r.status_code == 200:
raw_etag = r.headers.get('ETag') or r.headers.get('etag')
if raw_etag:
etag = raw_etag.strip('" \t').upper()
else:
print(f"Warning: No ETag received from server for part {part_num}")
continue
# Verify ETag matches local MD5
if etag == local_md5:
print(f"Got ETag for part {part_num}: {etag}")
success = True
break
else:
print(f"ETag mismatch for part {part_num}: expected {local_md5}, got {etag}")
print("Retrying...")
sleep(2 ** attempt)
else:
print(f"Chunk {part_num} failed: {r.status_code}, {r.text}")
sleep(2 ** attempt)
except Exception as e:
print(f"Chunk {part_num} error (attempt {attempt}): {e}")
if attempt < MAX_RETRIES:
sleep(2 ** attempt)
else:
print(f"Chunk {part_num} failed after {MAX_RETRIES} attempts.")
if not success:
print(f"Aborting upload due to failure in chunk {part_num}.")
return
uploaded_parts.append({"part_number": part_num, "etag": etag})
print("All chunks uploaded.")
complete_payload = {
"drive_id": DRIVE_ID,
"file_id": file_id,
"upload_id": upload_id,
"part_info_list": uploaded_parts
}
try:
resp = session.post(f"{API_BASE}/v2/file/complete", json=complete_payload, timeout=30)
result = resp.json()
if "file_id" in result:
print(f"Upload completed successfully: {filename}")
else:
print(f"Complete failed: {result}")
except Exception as e:
print(f"Complete request failed: {e}")
def main():
if len(sys.argv) < 2:
print("Usage: python3 aliyun_upload_path.py <local_file> [remote_path]")
print("Example:")
print(" python3 aliyun_upload_path.py test.txt")
print(" python3 aliyun_upload_path.py 2025-10-10-v4.zip bocheng-k8s")
sys.exit(1)
local_path = sys.argv[1]
remote_path = sys.argv[2] if len(sys.argv) > 2 else ""
if not os.path.exists(local_path):
print(f"Local file not found: {local_path}")
sys.exit(1)
if not os.path.isfile(local_path):
print("Only single file upload is supported.")
sys.exit(1)
target_folder_id = ensure_remote_dir(remote_path)
if not target_folder_id:
print("Failed to get target directory ID.")
sys.exit(1)
print(f"Target folder ID: {target_folder_id}")
upload_single_file_chunked(local_path, target_folder_id)
if __name__ == "__main__":
main()
七、使用方法
1. 保存脚本
nano aliyun_upload.py
# 粘贴上面代码,Ctrl+O 保存,Ctrl+X 退出
chmod +x aliyun_upload.py
2. 上传文件
# 上传单个文件到根目录
python3 aliyun_upload.py test.txt
# 上传文件到指定目录(自动创建 csdn)
python3 aliyun_upload.py test.txt csdn
# 上传整个目录
python3 aliyun_upload.py ./logs csdn/backups
八、常见问题与解决
| 问题 | 原因 | 解决方案 |
|---|---|---|
AccessTokenInvalid |
Token 过期或格式错误 | 重新抓包获取有效 token |
NotFound.Drive |
DRIVE_ID 错误 |
使用 default_drive_id,不是 domain_id |
InvalidRapidProof |
proof_code 计算错误 |
确保偏移 7 字节,读 8 字节 |
NameError: local_file |
变量名拼写错误 | 已修复 |
| URL 包含空格 | API_BASE 有空格 |
删除 https://api.aliyundrive.com 后的空格 |
九、安全建议
- 🔐 不要在代码中硬编码
ACCESS_TOKEN。 - 🔄 定期刷新 token(每 1~2 小时)。
- 📁 敏感脚本权限设为 600。
- 🛡️ 生产环境建议使用服务账户 +
refresh_token自动续期机制。
十、结语
您现在拥有了一个稳定、可靠、可维护的阿里云盘上传工具。只要确保:
- ✅
ACCESS_TOKEN有效 - ✅
DRIVE_ID = 5808324 - ✅
API_BASE无多余空格 - ✅ 环境变量已加载
更多推荐

所有评论(0)