牙叔教程 简略易懂
之前发了一篇教程 百度网盘5MB每秒-你本来就很快
浏览量还能够, 所以写个续集,
不明白原理的能够看之前的教程,
上一篇教程中选用的办法是扫描二维码授权, 今天咱们用别的一种办法授权;
咱们封装一下办法, 运用的语言是
- Node.js
其他语言能够运用 ChatGPT4 , 把Nodejs修改为其他语言
最终整合的代码中, 有下载进展, 便是我用 ChatGPT4 优化的.
过程
一共有两步
-
获取用户授权
-
下载文件
授权形式介绍
当时百度网盘开放平台支持三种授权形式:授权码形式(Authorization Code)、简化形式(Implicit Grant)、设备码形式(Device Code)。您能够依据本身事务,挑选合适的授权形式,完成用户授权。
三种形式首要区别如下:
授权形式 | 描绘 |
---|---|
授权码形式 (Authorization Code) | 用户授权后生成授权码 Code,开发者运用经过 Code 交换 Access Token。 |
简化形式 (Implicit Grant) | 无需经过 Code 交换 Access Token,直接获取 Access Token。 |
设备码形式 (Device Code) | 获取设备码,用户授权后,开发者运用经过设备码交换 Access Token。 |
前两种都要绑定自己的域名, 我没有域名, 所以我挑选第三个 设备码形式
设备码形式(Device Code)
对于弱输入设备,不支持浏览器或输入受限的设备(如儿童手表),推荐运用设备码形式接入授权。
开发者获取设备码,用户授权成功后,开发者经过设备码成功交换 Access Token。
用户授权有两种方法:一种是扫描二维码方法,另一种是输入用户码方法。关于用户码,在开发者获取设备码的一起,会回来用户码。
咱们看最终一句话, 用户授权有两种办法
- 扫描二维码
- 输入用户码
为了完成更便利的主动化下载文件, 咱们选用输入用户码的形式
授权时序图
这是百度网盘官方的图片
代码就不讲了, 我就只贴一下,
懂的就懂, 不明白的讲了也不明白, 不费那个劲
获取用户码
这些代码都是用 ChatGPT 写的
有图为证
const axios = require("axios");
const { AppID, Appkey, Secretkey, Signkey } = require("./config.js");
async function getDeviceCode() {
try {
const response = await axios.get("https://openapi.baidu.com/oauth/2.0/device/code", {
params: {
response_type: "device_code",
client_id: Appkey,
scope: "basic,netdisk",
},
headers: {
"User-Agent": "pan.baidu.com",
},
});
console.log(response.data);
} catch (error) {
console.log(error);
}
}
getDeviceCode();
他回来的字段是这样的
{
device_code: '7bb71f0xxxxxxxxxxx27',
user_code: 'mexxxxxxxxx',
verification_url: 'https://openapi.baidu.com/device',
qrcode_url: 'https://openapi.baidu.com/device/qrcode/001xxxxxxxxxxxa',
expires_in: 300,
interval: 5
}
首要字段的作用
- device_code 设备码, 后边要获取token, 就要运用他
- user_code 用户码, 百度网页验证的时分填写的东西
- verification_url, 百度的网页验证, 用于填写用户码 (二选一)
- qrcode_url, 授权的另一种方法, 这是二维码的链接 (二选一)
假如你运用qrcode_url, 那么就需要用户运用网盘客户端扫描该二维码;
假如你运用verification_url, 那么用户只需要输入用户码即可, 也便是user_code字段的值, 就像这样
成功授权后是页面是这样提示的
这样比扫描二维码便利, 不然还得自己拿个手机扫来扫去的.
授权现已ok了, 接下来咱们申请token
申请 Access Token
我原来的代码是Promise的, 我让ChatGPT改成async的
params中的code字段的值, 是上一次拜访回来的数据中的device_code
const axios = require("axios");
const { AppID, Appkey, Secretkey, Signkey, device_code } = require("./config.js");
async function getToken() {
try {
const response = await axios.get("https://openapi.baidu.com/oauth/2.0/token", {
params: {
grant_type: "device_token",
code: device_code,
client_id: Appkey,
client_secret: Secretkey,
},
headers: {
"User-Agent": "pan.baidu.com",
},
});
console.log(response.data);
} catch (error) {
console.log(error);
}
}
getToken();
回来的数据
{
expires_in: 2592000,
refresh_token: '127.11bbxxxxxxxxxxxxxxmg',
access_token: '126.29cxxxxxxxxxxxOg',
session_secret: '',
session_key: '',
scope: 'basic netdisk'
}
token有了今后, 就能够随心所欲了
我看看我网盘有没有大文件,
找到了, 有个游戏, 50MB
假如文件的名字是中文, 咱们需要编码, 就像你在浏览器的地址栏中, 看到的汉字一样,
中文编码
比方, 你在百度输入你好, 按下回车, 地址栏是这样的
,
假如你仿制黏贴, 会发现没有你好了, 呈现的是百分号表示的你好
https://www.baidu.com/s?wd=%E4%BD%A0%E5%A5%BD
百度文档是这样说的
他说dir字段, 假如有中文, 那么就要url编码, 你是不是也编码了?
是不是爆错了, 要么-7 要么-9
过错码
过错码 | 过错描绘 |
---|---|
-7 | 文件或目录无权拜访 |
-9 | 文件或目录不存在 |
你要是信了文档, 你就得栽个跟头, 十万八千里的那种, 直接到西天
丫的我测试了半天, 根本不必编码,
也许以前要吧, 可是现在, 此时此刻, 是不需要编码的.
文档忽悠了我, 心碎一地
文档右下角有个点评功能, 我给了二颗星, 而且给了原因,
希望官方人员, 能够及时更新文档
下载文件流程
- 指定要下载的文件的父文件夹
- 获取父文件夹下的子文件信息
- 下载文件
代码就不分开一个一个讲了, 直接合起来
config.js
module.exports = {
AppID: "xxx",
Appkey: "xxx",
Secretkey: "xxx",
Signkey: "xxx",
access_token: '1xxxx',
fs_id: "xxx",
device_code: "xxx",
};
main.js
const axios = require("axios");
const path = require("path");
const fs = require("fs");
const { AppID, Appkey, Secretkey, Signkey, device_code, access_token } = require("./config.js");
async function getFileList(directory) {
try {
const response = await axios.get("https://pan.baidu.com/rest/2.0/xpan/file", {
params: {
method: "list",
dir: directory,
order: "time",
start: 0,
limit: 10,
folder: 0,
access_token: access_token,
desc: 1,
},
headers: {
"User-Agent": "pan.baidu.com",
},
});
return response.data.list;
} catch (error) {
console.log(error);
}
}
async function getFileMetas(fs_id) {
try {
const response = await axios.get("http://pan.baidu.com/rest/2.0/xpan/multimedia", {
params: {
method: "filemetas",
access_token: access_token,
fsids: `[${fs_id}]`,
thumb: 0,
dlink: 1,
extra: 0,
},
headers: {
"User-Agent": "pan.baidu.com",
},
});
return response.data;
} catch (error) {
console.log(error);
}
}
function formatSize(size) {
if (size < 1024 * 1024) {
return (size / 1024).toFixed(2) + " KB";
} else {
return (size / (1024 * 1024)).toFixed(2) + " MB";
}
}
function downloadFile(dlink, fileSavePath) {
let url = `${dlink}&access_token=${access_token}`;
return new Promise((resolve, reject) => {
axios
.get(url, {
headers: {
"User-Agent": "pan.baidu.com",
Host: "d.pcs.baidu.com",
},
responseType: "stream",
})
.then((response) => {
const totalSize = response.headers["content-length"];
let downloadedSize = 0;
const writeStream = fs.createWriteStream(fileSavePath);
response.data.pipe(writeStream);
response.data.on("data", (chunk) => {
downloadedSize += chunk.length;
});
const printProgress = setInterval(() => {
const progress = ((downloadedSize / totalSize) * 100).toFixed(2);
console.log(`Downloaded: ${formatSize(downloadedSize)}, Progress: ${progress}%`);
}, 1000);
writeStream.on("finish", () => {
clearInterval(printProgress);
resolve(true);
});
writeStream.on("error", (error) => {
clearInterval(printProgress);
reject(error);
});
})
.catch((error) => {
console.log(error);
reject(false);
});
});
}
function getParentDirectory(filePath) {
let parentDirectory = path.dirname(filePath);
return parentDirectory;
}
async function downloadPanFile(panFilePath) {
let parentDirectory = getParentDirectory(panFilePath);
let fileList = await getFileList(parentDirectory);
const foundItem = fileList.find((item) => item.path === panFilePath);
if (!foundItem) {
console.log("文件不存在");
return;
}
const fileMetas = await getFileMetas(foundItem.fs_id);
const dlink = fileMetas.list[0].dlink;
let fileName = path.basename(panFilePath);
// 正则表达式匹配不合法文件名字符
const invalidCharacters = /[\/:"*?<>|]/g;
// 用空字符串替换不合法字符
const sanitizedFileName = fileName.replace(invalidCharacters, "");
fileName = sanitizedFileName.replace(/\s+/g, "-");
let fileSavePath = path.join(__dirname, fileName);
fileSavePath = path.resolve(fileSavePath);
let startTime = new Date().getTime();
await downloadFile(dlink, fileSavePath);
let endTime = new Date().getTime();
console.log(`下载耗时:${(endTime - startTime) / 1000}s`);
}
/* -------------------------------------------------------------------------- */
let panFilePath = "/eee/xxx/ccc/aaa.apk";
downloadPanFile(panFilePath);
代码中的下载文件进展, 以及 formatSize 办法, 都是用 ChatGPT4 主动修改的, 不必自己着手,
改代码, 便是一句话的事;
优化代码
你还能够仿制完好的代码, 让 ChatGPT4 优化它,
这是ChatGPT4给的代码优化的主张
I have made the following changes to the code:
Removed unnecessary variable assignment for parentDirectory and used it directly in getFileList() function call.
Removed unnecessary variable assignment for fileSavePath and used path.resolve() directly in its place.
Consolidated multiple lines of code into single lines where appropriate for better readability.
Removed unnecessary blank lines.
第一个优化点,
把
function getParentDirectory(filePath) {
let parentDirectory = path.dirname(filePath);
return parentDirectory;
}
改为
function getParentDirectory(filePath) {
return path.dirname(filePath);
}
第二个优化点
把
let fileSavePath = path.join(__dirname, fileName);
fileSavePath = path.resolve(fileSavePath);
改为
let fileSavePath = path.resolve(__dirname, fileName);
下载速度
日志一秒打印一次
Downloaded: 7.50 MB, Progress: 15.77%
Downloaded: 14.00 MB, Progress: 29.44%
Downloaded: 21.50 MB, Progress: 45.21%
Downloaded: 28.00 MB, Progress: 58.88%
Downloaded: 35.93 MB, Progress: 75.54%
Downloaded: 42.00 MB, Progress: 88.31%
下载耗时:7.668s
- 文件大小 47.56MB
- 下载时刻 7.668s
- 下载速度 6.20MB每秒
ChatGPT对本教程的作用
- 代码, 我是直接仿制黏贴的百度官方文档, 然后跟他说, 这是文档接口, 写出代码, 这样就有了根本代码
- 假如他出的是Promise的风格, 我会让让改成async的风格
- 让他添加了下载进展, 而且小于1024kb, 就用kb显现, 否则用mb显现
- 优化大块的代码
ChatGPT联网版, Stable Diffusion画图, 这个星球全都有, 低沉运用, 别别传