尧图网络 高端网站定制 · 原创设计
免费咨询热线
400-888-6620
免费获取方案
百度网盘批量转存工具开发:从接口解析到并发工程化
简介这是一款面向百度网盘批量转存的浏览器扩展源码适合计算机、数学、电子信息等专业学生作为课程设计、期末大作业或毕业设计参考资料可有效解决多文件手动逐条转存效率低、重复操作多的问题同时也能帮助前端开发者快速了解浏览器扩展的完整开发流程。压缩包共12个文件以JavaScript逻辑脚本为主配合HTML弹窗页面、CSS进度样式、PNG/JPG图标资源和manifest配置文件整体仅31KB代码精简、结构清晰便于按模块研读与调试。目前已有663人学习下载具备一定参考热度。源码完整可运行涵盖弹出窗口、进度展示、批量处理与配置声明等完整实现读者既能借鉴其界面交互和数据请求写法也可在此基础上升级为支持更多网盘或自定义转存任务是练手与二次开发的不错起点。1. 批量转存不是下载先看百度网盘转存的接口本质网上流传的“百度网盘批量转存工具源码.zip”下载下来后大概率是一堆.py文件加一份写得不完整的 README。真正跑不起来的原因并不是代码本身而是它默认你已经知道转存不是下载而是把别人分享的文件“保存到你自己网盘”的一次接口调用。手动操作时你只需要打开分享链接、点“保存到网盘”批量化之后就要自己处理登录态、分享信息解析、签名参数、并发和重试。这篇文章把这套链路拆开讲清楚先理解接口再写最小批量脚本最后补上工程化兜底。与其在“免费 python 源码大全”里碰运气不如自己把这条转存链路完整搭一遍跑通了它就是个能长期改的框架而不是一个解不开的谜。2. 从分享链接到转存参数解析分享页与构造 save 请求2.1 手动点“保存到网盘”时浏览器实际做了什么打开一个带提取码的分享链接手动保存到网盘背后至少发生了三次请求第一次打开分享详情页拿到分享者 UIDuk、分享 IDshareid、文件列表fid_list第二次提交提取码换回一个用于转存的凭证第三次才是真正执行保存动作也就是share/save接口。常见做法是直接看浏览器开发者工具里 Network 面板的请求记录把“保存到网盘”前后那几条 XHR 请求的 URL、参数和返回结构抄下来。这个工具的“源码”价值其实就是对这三步请求的封装。拿到手之后你要先确认它请求的 URL 和参数跟当前网页版是否一致因为百度网盘前端接口的参数名变动并不少见。请求链路里有一个关键点转存动作本身是服务端到服务端的文件复制不经过本地流量。也就是说批量转存的耗时取决于接口响应速度而不是你的带宽。这决定了后面做并发设计时可以走线程池而不是协程池。2.2 登录态BDUSS 是唯一鉴权依据所有转存请求都依赖登录态。常见做法是从浏览器 Cookie 里取BDUSS它是账号凭证的核心STOKEN一类字段在某些接口里也会用到。import requests session requests.Session() session.headers.update({ User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36, Referer: https://pan.baidu.com/ }) session.cookies.set(BDUSS, 你的BDUSS值)逻辑说明session.cookies.set把BDUSS注入到后续所有请求的 Cookie 头里。User-Agent和Referer也要带上否则部分接口直接拒绝。写工具时应把BDUSS放到独立配置文件里而不是写死在源码中这样源码 zip 给别人看时不会泄号。注意BDUSS 等同于网盘账号的登录凭证泄漏后别人可以直接操作你的网盘。做分享或开源时务必从代码里剥离。2.3 解析分享详情拿 shareid、uk、fid_list这一步的行为是先请求分享链接对应的详情页从返回内容里解析出分享信息如果链接带提取码还需要先提交提取码。import re import requests def get_share_detail(session, share_url, pwdNone): # 提取分享链接中的 surl 标识 surl share_url.split(/s/)[-1].split(?)[0] url https://pan.baidu.com/s/ surl resp session.get(url, allow_redirectsTrue) text resp.text # 部分页面会把 shareid/uk 直接写在 HTML 的 data 属性里 shareid_match re.search(rshareid:\s*(\d), text) uk_match re.search(ruk:\s*(\d), text) # 较新的网页端是 SPA分享页 HTML 里可能拿不到完整参数 # 常见做法是改请求 web/share/list 接口拿 JSON if (list) in text or shareid_match is None: api_url https://pan.baidu.com/share/list params { uk: uk_match.group(1) if uk_match else , shareid: shareid_match.group(1) if shareid_match else , order: time, desc: 1, showempty: 0, web: 1, page: 1, num: 1000, } if pwd: params[pwd] pwd api_resp session.get(api_url, paramsparams) return api_resp.json() return text参数说明surl是链接里的短标识从/s/后面取一段去掉查询参数。先直接 GET 分享页部分老页面会把shareid和uk直接塞在 HTML 里正则能拿到。如果拿不到就请求share/list接口num1000表示单页返回 1000 个文件条目超大批量时要翻页。带提取码时把pwd加进查询参数有些接口还要额外 POST 一次提取码校验。手头拿到别人的工具源码时优先看这个函数如果它还在解析旧版 HTML 结构基本可以判断已经失效。新版接口返回的是 JSON字段更稳定。2.4 构造转存请求save 接口与签名参数执行转存的核心请求是share/save常见参数如下参数含义来源shareid分享 ID分享详情返回from分享者标识填uk值分享详情返回sekey转存凭证提取码校验后返回提取码校验/randskfid_list要转存的文件 ID 列表file_list返回path你网盘里的目标目录自己指定sign动态签名网页端 JS 生成timestamp时间戳网页端 JS 生成sign和timestamp是从网盘首页加载的 JS 文件里生成出来的。常见做法是下载首页引用的 JS用正则抓取生成逻辑然后在工具里复刻一遍。import re, time, hashlib def get_sign(session): home session.get(https://pan.baidu.com/) js_urls re.findall(rscript[^]src([^]\.js[^]*), home.text) for js_url in js_urls[:10]: js_text session.get(js_url if js_url.startswith(http) else https: js_url).text sign_match re.search(rsign\s*:\s*function[^}], js_text) if sign_match: # 实际生产环境是从匹配到的逻辑里计算而成这里只做占位 break timestamp int(time.time() * 1000) return timestamp, timestamp # 返回占位需按抓到的逻辑替换逻辑说明这个函数的核心思路是“动态获取签名逻辑”因为 JS 文件名带版本号写死 URL 会随版本更新失效。代码里sign_match找到的是一段函数体需要把它转换成 Python 实现比如用exec、py_mini_racer或直接人工翻译。注意签名生成逻辑是接口能否调通的关键。如果源码里sign是写死的常量说明它很快就会过期如果根本没有sign参数说明它对应的可能是旧版接口能不能用取决于当前服务端是否还兼容。3. 批量与并发用 Python 把转存循环改成可控任务流3.1 输入清单与任务组织批量转存的输入通常是一个文本文件每一行一个分享链接可选的提取码用空格分隔。这个格式足够简洁也方便和表格工具互导。https://pan.baidu.com/s/1ABC123… abcd https://pan.baidu.com/s/1DEF456…对应的数据结构用dataclass定义比裸字典清晰from dataclasses import dataclass dataclass class ShareTask: url: str pwd: str | None None target_dir: str /来自批量转存 def to_skip_key(self) - str: # 用于后续增量记录 return self.url.split(/s/)[-1] (self.pwd or )to_skip_key的用途是关键批量转存最怕任务跑到一半中断下次全量重跑。用链接标识加提取码拼一个唯一键结合断点记录就能跳过已完成的条目。3.2 串行版批量转存先把链路跑通并发之前先写一份串行版本保证单个任务能从链接到转存完整走通。这份代码也是后续排错的基准。import json import time import requests from pathlib import Path def load_tasks(file_path: str) - list[ShareTask]: tasks [] for line in Path(file_path).read_text(encodingutf-8).splitlines(): line line.strip() if not line or line.startswith(#): continue parts line.split(maxsplit1) tasks.append(ShareTask(urlparts[0], pwdparts[1] if len(parts) 1 else None)) return tasks def process_one(session, task: ShareTask) - dict: info get_share_detail(session, task.url, task.pwd) fid_list [item[fs_id] for item in info.get(list, [])] if not fid_list: return {task: task.url, status: skipped, reason: empty_fid} params { shareid: info[shareid], from: info[uk], sekey: info.get(sekey, ), fid_list: json.dumps(fid_list), path: task.target_dir, sign: get_sign(session)[0], timestamp: get_sign(session)[1], } resp session.post(https://pan.baidu.com/share/save, paramsparams) return {task: task.url, status: resp.json().get(errno), detail: resp.json()} tasks load_tasks(links.txt) session requests.Session() session.cookies.set(BDUSS, 你的BDUSS值) for task in tasks: result process_one(session, task) print(result) time.sleep(1) # 避免请求过快逻辑说明fid_list必须是 JSON 数组字符串不能直接传 Python 列表requests会把列表参数编码成多个同名键。path指向你网盘里的目标目录如果目录不存在需要先调create接口或手动在网盘里建好。循环末尾的sleep(1)是最简单的限速手段。3.3 并发提速为什么用线程池而不是 asyncio接口调用是网络 IO 密集型操作单个任务的大头时间花在等待响应上。常见做法是用ThreadPoolExecutor因为requests是同步阻塞调用起多线程最简单asyncio配httpx也可以但改造成本高出错时不好定位。from concurrent.futures import ThreadPoolExecutor, as_completed MAX_WORKERS 5 def run_batch(tasks, session_factory): with ThreadPoolExecutor(max_workersMAX_WORKERS) as pool: futures { pool.submit(process_one, session_factory(), task): task for task in tasks } for future in as_completed(futures): task futures[future] try: result future.result() print(task.url, result[status]) except Exception as e: print(task.url, failed, repr(e))session_factory是每次提交任务时创建一个新会话不要多个线程共用一个requests.Session。原因有两个一是Session内部维护的 Cookie 和连接池不是完全线程安全的二是某个线程请求异常导致连接池污染时会连累其他任务。3.4 并发上限与限速参数怎么定MAX_WORKERS不是越大越好。网盘服务端对单账号的请求频率有限制超过阈值会返回限流错误码。我一般从 3 开始调观察两个指标成功率是否下降、单个请求响应时间是否显著变长。如果errno里频繁出现限流类错误就把并发降回去。另外一个实用做法是给每个任务加随机间隔import random # 在 process_one 开头执行 time.sleep(random.uniform(0.3, 0.8))随机间隔的好处是避免所有线程在同一时刻集中发请求形成明显的请求峰。固定间隔在并发场景下反而容易踩限频阈值。4. 工程化兜底重试、限速、增量记录与结果校验4.1 按返回码决定是否重试批量转存跑几百条链接时网络抖动和临时限流是常态。重试策略不能所有错误一视同仁否则会把永久性失败的任务反复跑好几遍。RETRYABLE_ERRNO {-9, -10, 0, 1} MAX_RETRY 3 def process_with_retry(session, task): for attempt in range(MAX_RETRY): result process_one(session, task) errno result[status] if errno 0: return result if errno in RETRYABLE_ERRNO and attempt MAX_RETRY - 1: wait (2 ** attempt) random.uniform(0, 1) time.sleep(wait) continue return result return result参数说明MAX_RETRY是重试次数wait 2 ** attempt是指数退避错误码0表示接口返回成功但可能转存被异步执行需要二次校验确认所以也放进可重试集合。注意永久性错误不要重试。常见的永久性失败包括分享链接已失效、文件已被删除、提取码错误重试只会浪费请求额度应该在日志里直接标记为SKIP。4.2 增量记录中断后不用重头跑大批量操作不能没有断点记录。常见做法是维护一个done.txt每成功一条就追加一行下次启动时先读取这份记录跳过已完成的条目。def load_done(skip_path: str) - set: if not Path(skip_path).exists(): return set() return set(Path(skip_path).read_text(encodingutf-8).splitlines()) def append_done(skip_path: str, key: str): with open(skip_path, a, encodingutf-8) as f: f.write(key \n) # 主流程里 done_set load_done(done.txt) for task in tasks: key task.to_skip_key() if key in done_set: print(task.url, already done) continue result process_with_retry(session, task) if result[status] 0 and verify_target(task): append_done(done.txt, key)verify_target是结果校验函数。只记录“确认转存成功”的条目而不是“接口返回成功”的条目这样断点记录才有意义。4.3 转存后的二次校验share/save返回errno0只说明请求已受理文件可能还在后台拷贝尤其是超大目录。所以我一般会在转存后延迟几秒再调file/list检查目标目录里的文件数是否增加了。def verify_target(session, task) - bool: time.sleep(5) url https://pan.baidu.com/api/list params {dir: task.target_dir, order: time, desc: 1} resp session.get(url, paramsparams) data resp.json() return data.get(errno) 0 and len(data.get(list, [])) 0逻辑说明这里用list接口读目标目录只验证“目录里有没有东西”不精确比对文件数量。要精确比对就需要把get_share_detail里拿到的fid_list数量与该接口返回条目数做对比数量一致才算完整转存。4.4 常见失败场景与排查方向现象可能原因排查手段errno-6或类似鉴权错误BDUSS 过期或被风控重新登录网页版检查 Cookie 是否失效sign相关报错签名算法过期重新抓取首页 JS更新签名生成逻辑errno0但目录为空异步拷贝未完成加大verify_target的等待时间转存成功但文件缺失部分文件被分享者删除比对fid_list与目录实际条目请求全部超时请求频率过高被临时限制降低并发加大随机 sleep 间隔这四个场景覆盖了批量转存工具 90% 以上的问题。任何一行报错先对照这个表定位是“登录态问题”“接口版本问题”还是“频率限制问题”再动手改代码。5. 验证与排错用 errno 和文件清单确认每次转存成功批量工具上线前先拿 3 条测试链接跑串行版。三条测试链接分别覆盖三种情况无提取码链接、带提取码链接、包含多层级目录的分享链接。跑完去网页端核对路径确认目录结构和文件数量与预期一致。这一步通过后再把MAX_WORKERS调到 5 跑全量。日志是唯一可靠的排错依据。每一行输出建议固定格式2025-01-12 10:23:45 | OK | /s/ABC123 | 20 files | 12.3s 2025-01-12 10:24:01 | SKIP | /s/DEF456 | already done 2025-01-12 10:24:30 | FAIL | /s/GHI789 | errno-18 link expired这个格式包含时间、状态、任务标识、文件数和耗时。跑完批量任务后用grep FAIL看失败列表用grep OK | wc -l统计成功数。耗时列还能帮你判断限速情况如果单个任务平均耗时从 5 秒涨到 15 秒说明请求已经被服务端降速处理。最后一个小技巧转存后校验不要只看接口返回码。在verify_target里对比fid_list的数量与list接口返回的条目数不一致时主动在日志里标PARTIAL并把任务写进单独的need_check.txt而不是直接标记失败。这样处理的好处是能区分“转存完全失败”和“部分文件丢失”后者往往是因为分享者在转存过程中删除了文件重试也解决不了人工核对更合适。本文还有配套的精品资源点击获取
RELATED

相关推荐

Langfuse 中的 ClickHouse 最佳实践:Schema 设计、查询优化与写入策略全解析

Langfuse 中的 ClickHouse 最佳实践:Schema 设计、查询优化与写入策略全解析

Langfuse 中的 ClickHouse 最佳实践:Schema 设计、查询优化与写入策略全解析 【免费下载链接】langfuse 🪢 Open source AI engineering platform: LLM evals, observability, metrics, prompt management, playground, datasets. Integrates with OpenT…

📅 2026/9/10 2:33:59
2026企业AI办公工具选型指南:建立适配业务的评估框架

2026企业AI办公工具选型指南:建立适配业务的评估框架

企业引入AI办公工具的过程中,很容易陷入表层对比的误区。不少IT负责人会把功能清单长度、公开报价、市场声量作为主要判断依据,拿到多款产品的功能对照表逐项勾选,希望找到覆盖最多能力的平台。部分采购决策还会单纯参考同行业采购案例&#…

📅 2026/9/10 2:28:59
2026年进销存智能化趋势:企业选型需要把握哪些核心方向?

2026年进销存智能化趋势:企业选型需要把握哪些核心方向?

本文要点:本文解读2026年进销存智能化(自动补货、异常预警、AI记账)趋势,分析企业选型应优先评估的数据贯通、规则引擎与低门槛迭代三类能力,并盘点轻流及多家主流工具的应对思路,适合计划升级库存管理的中…

📅 2026/9/10 2:28:59
MORE NEWS

更多资讯

📰

UEFI与ESP分区全解:从启动链原理到引导修复实战

折腾机器多年的朋友应该都有一个共识:只要跟“启动”沾边的问题,十有八九最后都会绕到同一个地方——ESP分区。我前阵子帮同事救一台Win10更新后卡grub rescue的本子,从磁盘管理看到底,最后发现EFI系统分区好好的,但里…

📰

Hermes智能体更新与维护:面向AI Agent的运维SLO实践

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

📰

补全项目信息,获得高质量技术博客的生成基础

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

📰

洛阳钼业7年矿山无人化演进:最稳的矿区自动驾驶落地路径

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

📰

如何用 RxJava 的 ParallelFlowable 做并行数据处理?parallel、runOn 与 sequential 用法及适用边界

如何用 RxJava 的 ParallelFlowable 做并行数据处理?parallel、runOn 与 sequential 用法及适用边界 【免费下载链接】RxJava RxJava – Reactive Extensions for the JVM – a library for composing asynchronous and event-based programs using observable sequ…

📰

Java+大数据+AI全能工程师知识体系与实战避坑指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

TODAY

今日更新

THIS WEEK

本周精选

THIS MONTH

本月热门

读完文章,想聊聊您的网站?

告诉我们您的行业与需求,资深顾问一对一梳理方案与报价,全程免费。

📞 💬