Ruby ruby 百度网盘转存

gh_ruby · 2022年04月19日 · 828 次阅读

百度网盘转存流程

  1. 需要在百度网盘开放平台控制台添加应用
  2. 点击应用可以查看:AppKey、SecretKey;分别对应接口中的 client_id、client_secret
  3. 授权
    • 授权码模式授权
      • (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(不支持刷新)
  4. 通过 Baiduyun.get_shorturl 获取 shorturl、password
  5. 通过 Baiduyun.sekey_verify 验证分享链接,并获取 randsk(查询分享文件信息时的 sekey 字段)
  6. 通过 Baiduyun.attachment_lists 查询分享文件信息,并获取 share_id、uk、fs_id(用于转存)
  7. 通过 Baiduyun.attachment_transfer 转存分享链接
  8. 通过 Baiduyun.fsid_list_all 获取分享数据和转存后的 fs_id(用于获取下载链接)
  9. 通过 Baiduyun.dlinks 获取 dlink
  10. 通过 Baiduyun.download 下载文件

注意事项

  1. 建议通过授权码模式授权获取 token;后续刷新 token 通过 refresh_tokens 刷新
  2. 无需开启企业权限也可转存其他人发起的链接
  3. access_token 有效期 30 天;refresh_token 有效期 10 年
  4. 请求字段
    • sekey:密码验证后的 randsk
    • randsk 获取后需要 URI.decode
    • shareid:获取链接数据列表后的 share_id
    • uk:获取链接数据列表后的 uk
    • fsidlist、fsids 均为数组
    • fsids:当前账号查询出的 fs_id,并非分享链接的 fsid
    • recursion 是否递归,0 为否,1 为是,默认为 0,官方建议不超过每分钟 8-10 次
  5. 获取的 dlink 会重定向
  6. 下载速度依据百度云的下载速度大概 50kb/s,开通 vip 后速度大概 10M/s
  7. 转存流程
    • (1.验证密码 (获取 randsk)
    • (2.获取链接数据列表 (获取 share_id、uk)
    • (3.转存
  8. 下载流程
    • (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

使用参考

  1. 获取 token
    • (1.Baiduyun.access_token
    • 或者:
    • (1.Baiduyun.code
    • (2.Baiduyun.tokens(code)
  2. 链接转存
    • (1.Baiduyun.sekey_verify(shorturl, password)
    • (2.Baiduyun.attachment_lists(shorturl, sekey)
    • (3.attachment_transfer(shareid, uk, sekey, fsidlist, path)
  3. 下载
    • (1.fsid_search(file_name, dir)
    • (2.dlinks(fsids)
    • (3.download(dlink,file_name)
  4. 示例
# 转存分享链接代码示例
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 新手,还望各位大佬多指教😆

暂无回复。
需要 登录 后方可回复, 如果你还没有账号请 注册新账号