百度网盘转存流程
- 需要在百度网盘开放平台控制台添加应用
- 点击应用可以查看:AppKey、SecretKey;分别对应接口中的 client_id、client_secret
- 授权
- 授权码模式授权
- (1.通过 Baiduyun.code 方法获取链接
- (2.在浏览器登录百度云账号,输入获取的链接
- (3.点击授权 (勾选允许创建文件夹并读写数据)
- (4.复制授权码,通过 Baiduyun.tokens 方法获取链接
- (5.获取 refresh_token、access_token(支持刷新)
- (6.access_token 失效后可通过 Baiduyun.refresh_tokens 方法刷新
- 简化模式授权
- (1.通过 Baiduyun.access_token 方法获取链接
- (2.在浏览器登录百度云账号,输入获取的链接
- (3.点击授权 (勾选允许创建文件夹并读写数据)
- (4.在地址栏获取 access_token(不支持刷新)
- 通过 Baiduyun.get_shorturl 获取 shorturl、password
- 通过 Baiduyun.sekey_verify 验证分享链接,并获取 randsk(查询分享文件信息时的 sekey 字段)
- 通过 Baiduyun.attachment_lists 查询分享文件信息,并获取 share_id、uk、fs_id(用于转存)
- 通过 Baiduyun.attachment_transfer 转存分享链接
- 通过 Baiduyun.fsid_list_all 获取分享数据和转存后的 fs_id(用于获取下载链接)
- 通过 Baiduyun.dlinks 获取 dlink
- 通过 Baiduyun.download 下载文件
注意事项
- 建议通过授权码模式授权获取 token;后续刷新 token 通过 refresh_tokens 刷新
- 无需开启企业权限也可转存其他人发起的链接
- access_token 有效期 30 天;refresh_token 有效期 10 年
- 请求字段
- sekey:密码验证后的 randsk
- randsk 获取后需要 URI.decode
- shareid:获取链接数据列表后的 share_id
- uk:获取链接数据列表后的 uk
- fsidlist、fsids 均为数组
- fsids:当前账号查询出的 fs_id,并非分享链接的 fsid
- recursion 是否递归,0 为否,1 为是,默认为 0,官方建议不超过每分钟 8-10 次
- 获取的 dlink 会重定向
- 下载速度依据百度云的下载速度大概 50kb/s,开通 vip 后速度大概 10M/s
- 转存流程
- (1.验证密码 (获取 randsk)
- (2.获取链接数据列表 (获取 share_id、uk)
- (3.转存
- 下载流程
- (1.获取数据 fsid
- (2.获取 dlink
- (3.下载
参考代码
require 'rest-client'
require 'json'
class Baiduyun
class << self
BASE_URL = "https://openapi.baidu.com"
BAIDUYUN_URL = "https://pan.baidu.com"
# 使用前填入账号数据
CLIENT_ID = ""
CLIENT_SECRET = ""
# 有效期30天
ACCESS_TOKEN = ""
# 有效期10年
REFRESH_TOKEN = ""
# 需登录账号,不支持刷新
def access_token
url = "#{BASE_URL}/oauth/2.0/authorize?"
params = {
"response_type": "token",
"client_id": CLIENT_ID,
"redirect_uri": "oob",
"scope": "basic,netdisk",
"display": "popup",
}
params.each do |key, value|
url += "#{key}=#{value}&"
end
url.chop!
end
# 需要登录账号
def code
url = "#{BASE_URL}/oauth/2.0/authorize?"
params = {
"response_type": "code",
"client_id": CLIENT_ID,
"redirect_uri": "oob",
"scope": "basic,netdisk",
"display": "popup",
}
params.each do |key, value|
url += "#{key}=#{value}&"
end
url.chop!
end
# 获取access_token、refresh_token,需登录账号
def tokens(code)
url = "#{BASE_URL}/oauth/2.0/token?"
params = {
"grant_type": "authorization_code",
"code": code,
"client_id": CLIENT_ID,
"client_secret": CLIENT_SECRET,
"redirect_uri": "oob",
}
params.each do |key, value|
url += "#{key}=#{value}&"
end
url.chop!
end
# 无需登录账号
def refresh_tokens
url = "#{BASE_URL}/oauth/2.0/token"
params = {
"grant_type": "refresh_token",
"refresh_token": REFRESH_TOKEN,
"client_id": CLIENT_ID,
"client_secret": CLIENT_SECRET,
}
result = RestClient::Request.execute(
method: :get,
url: url,
timeout: 30,
headers: {params: params}
)
JSON.parse(result)
end
# 新建文件夹
def create_dir(path)
url = "#{BAIDUYUN_URL}/rest/2.0/xpan/file"
params = {
"method": "create",
"access_token": ACCESS_TOKEN,
}
body = {
"path": path,
"size": 0,
"isdir": '1',
"block_list": "[]",
"rtype": 0,
}
result = RestClient::Request.execute(
method: :post,
url: url,
timeout: 30,
payload: body,
headers: {:params => params}
)
JSON.parse(result)
end
# url为分享链接,例如:'hi,这是我用百度网盘分享的文件~复制这段内容打开「百度网盘」APP即可获取。链接:https://pan.baidu.com/s/1QTi5vrn29N9-CvAtoC-08A 提取码:0p32'
def get_shorturl(url)
if url && (url.include? BAIDUYUN_URL)
link_start = url.index('http')
link_end = url.index('提')
baidu_link = url[link_start...link_end].strip
baidu_link_end = baidu_link.index('?')
baidu_link = baidu_link[0...baidu_link_end] if baidu_link_end
baidu_password = url[link_end + 4..url.length].strip
shorturl = ""
RestClient.get(baidu_link) do |response|
if [301, 302, 303, 307].include? response.code
redirected_url = response.headers[:location]
shorturl_end = redirected_url.index('surl=')
shorturl = redirected_url[shorturl_end + 5..redirected_url.length].strip
end
end
{"shorturl" => shorturl, "password" => baidu_password}
end
end
# 验证分享链接
def sekey_verify(shorturl, password)
url = "#{BAIDUYUN_URL}/rest/2.0/xpan/share"
params = {
"method": "verify",
"surl": shorturl,
}
body = {
"pwd": password
}
result = RestClient::Request.execute(
method: :post,
url: url,
timeout: 30,
payload: body,
headers: {:Referer => "pan.baidu.com", :params => params}
)
JSON.parse(result)
end
# 获取分享链接数据
def attachment_lists(shorturl, sekey)
url = "#{BAIDUYUN_URL}/rest/2.0/xpan/share"
params = {
"method": "list",
"shorturl": shorturl,
"sekey": sekey,
"page": "1",
"num": "100",
"root": "1",
"fid": "0"
}
result = RestClient::Request.execute(
method: :get,
url: url,
timeout: 30,
headers: {params: params}
)
JSON.parse(result)
end
# 获取分享链接详情
def attachment_info(shareid, uk, sekey)
url = "#{BAIDUYUN_URL}/api/shorturlinfo"
params = {
"shareid": shareid,
"uk": uk,
"spd": sekey,
}
result = RestClient::Request.execute(
method: :get,
url: url,
timeout: 30,
headers: {params: params}
)
JSON.parse(result)
end
# 百度云转存
def attachment_transfer(shareid, uk, sekey, fsidlist, path="/test")
url = "#{BAIDUYUN_URL}/rest/2.0/xpan/share"
params = {
"method": "transfer",
"access_token": ACCESS_TOKEN,
"shareid": shareid,
"from": uk,
}
body = {
"sekey": sekey,
"fsidlist": "#{fsidlist}",
"path": path,
}
header = {
"Referer": "pan.baidu.com",
}
result = RestClient::Request.execute(
method: :post,
url: url,
timeout: 30,
payload: body,
headers: {:Referer=>"pan.baidu.com", :params => params}
)
JSON.parse(result)
end
# 获取百度云文件列表
def fsid_list(dir="/test")
url = "#{BAIDUYUN_URL}/rest/2.0/xpan/file"
params = {
"method": "list",
"access_token": ACCESS_TOKEN,
"dir": dir,
"web": "1",
}
result = RestClient::Request.execute(
method: :get,
url: url,
timeout: 30,
headers: {params: params}
)
JSON.parse(result)
end
# 获取百度云文件列表,recursion是否递归,0为否,1为是,默认为0
def fsid_list_all(dir, recursion=0)
url = "#{BAIDUYUN_URL}/rest/2.0/xpan/multimedia"
params = {
"method": "listall",
"access_token": ACCESS_TOKEN,
"path": dir,
"recursion": recursion
}
result = RestClient::Request.execute(
method: :get,
url: url,
timeout: 30,
headers: {params: params}
)
JSON.parse(result)
end
# 查询百度云指定文件
def fsid_search(file_name,dir="/test")
url = "#{BAIDUYUN_URL}/rest/2.0/xpan/file"
params = {
"method": "search",
"access_token": ACCESS_TOKEN,
"dir": dir,
"web": "1",
"page": "1",
"num": "2",
"key": file_name,
}
result = RestClient::Request.execute(
method: :get,
url: url,
timeout: 30,
headers: {params: params}
)
JSON.parse(result)
end
# 查询百度云文件dlink
def dlinks(fsids)
url = "#{BAIDUYUN_URL}/rest/2.0/xpan/multimedia"
params = {
"method": "filemetas",
"access_token": ACCESS_TOKEN,
"thumb": "1",
"dlink": "1",
"extra": "1",
"fsids": "#{fsids}",
}
result = RestClient::Request.execute(
method: :get,
url: url,
timeout: 30,
headers: {params: params}
)
JSON.parse(result)
end
# 下载百度文件
def download(dlink,file_name)
url = dlink
params = {
"access_token": ACCESS_TOKEN,
}
header = {
"User-Agent" => "pan.baidu.com",
"params" => params
}
RestClient::Request.execute(method: :get, url: url, timeout: 30, headers: header) do |response|
if [301, 302, 303, 307].include? response.code
redirected_url = response.headers[:location]
File.open(file_name, "wb") do |f|
f.write(RestClient.get(redirected_url))
end
end
end
end
end
end
使用参考
- 获取 token
- (1.Baiduyun.access_token
- 或者:
- (1.Baiduyun.code
- (2.Baiduyun.tokens(code)
- 链接转存
- (1.Baiduyun.sekey_verify(shorturl, password)
- (2.Baiduyun.attachment_lists(shorturl, sekey)
- (3.attachment_transfer(shareid, uk, sekey, fsidlist, path)
- 下载
- (1.fsid_search(file_name, dir)
- (2.dlinks(fsids)
- (3.download(dlink,file_name)
- 示例
# 转存分享链接代码示例
links = "hi,这是我用百度网盘分享的内容~复制这段内容打开「百度网盘」APP即可获取 链接:https://pan.baidu.com/s/1OZGBWaLubwzY_cA_LRp78Q 提取码:9h5x"
shorturl_res = Baiduyun.get_shorturl links
shorturl = shorturl_res["shorturl"]
password = shorturl_res["password"]
if shorturl
verify_res = Baiduyun.sekey_verify shorturl, password
if verify_res["errno"] == 0
randsk = URI.decode(verify_res["randsk"])
lists_res = Baiduyun.attachment_lists shorturl, randsk
if verify_res["errno"] == 0
attachment_lists = lists_res["list"]
shareid = lists_res["share_id"]
uk = lists_res["uk"]
file_list = []
attachment_lists.each do |file|
file_list.push(file["fs_id"].to_i)
end
Baiduyun.attachment_transfer shareid, uk, randsk, file_list
end
end
end
# 下载文件代码示例
file_list_all_res = Baiduyun.fsid_list_all '/test/test',1
if file_list_all_res["errno"] == 0
file_list = []
file_list.push(file_list_all_res["list"][0]["fs_id"].to_i)
if file_list
dlinks_res = Baiduyun.dlinks file_list
puts dlinks_res
if dlinks_res["errno"] == 0
dlink = dlinks_res["list"][0]["dlink"]
file_name = dlinks_res["list"][0]["filename"].gsub(' ','')
if dlink
Baiduyun.download dlink, file_name
end
end
end
end
作为一名 ruby 新手,还望各位大佬多指教