开启辅助访问 切换到宽版

精易论坛

 找回密码
 注册

QQ登录

只需一步,快速开始

用微信号发送消息登录论坛

新人指南 邀请好友注册 - 我关注人的新帖 教你赚取精币 - 每日签到


求职/招聘- 论坛接单- 开发者大厅

论坛版规 总版规 - 建议/投诉 - 应聘版主 - 精华帖总集 积分说明 - 禁言标准 - 有奖举报

查看: 982|回复: 1
收起左侧

[已解决] 百d网盘分享转存Python谁能转一个易语呀。一起分享一下

 关闭 [复制链接]
结帖率:100% (45/45)
发表于 2021-3-19 15:45:04 | 显示全部楼层 |阅读模式   湖北省仙桃市
5精币
  1. import requests, re, urllib, os, time


  2. class BaiduYunTransfer:

  3.     headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.116 Safari/537.36',
  4.             'Referer': 'pan.baidu.com'}

  5.     universal_error_code = {'2': '参数错误。检查必填字段;get/post 参数位置',
  6.                             '-6': '身份验证失败。access_token 是否有效;部分接口需要申请对应的网盘权限',
  7.                             '31034': '命中接口频控。核对频控规则;稍后再试;申请单独频控规则',
  8.                             '42000': '访问过于频繁',
  9.                             '42001': 'rand校验失败',
  10.                             '42999': '功能下线',
  11.                             '9100': '一级封禁',
  12.                             '9200': '二级封禁',
  13.                             '9300': '三级封禁',
  14.                             '9400': '四级封禁',
  15.                             '9500': '五级封禁'}


  16.     def __init__(self, api_key, secret_key, share_link, password, dir):
  17.         self.api_key = api_key
  18.         self.secret_key = secret_key
  19.         self.share_link = share_link
  20.         self.password = password
  21.         self.dir = dir

  22.         if self.init_token() and self.get_surl() and self.get_sekey() and self.get_shareid_and_uk_and_fsidlist():
  23.             self.file_transfer()


  24.     def apply_for_token(self):
  25.         '''
  26.         获取应用授权的流程:
  27.         先获取授权码code,再通过code得到token(access_token和refresh_token)
  28.         详情参见:https://pan.baidu.com/union/document/entrance#3%E8%8E%B7%E5%8F%96%E6%8E%88%E6%9D%83
  29.         '''

  30.         '''
  31.         获取code
  32.         参数:
  33.         response_type       固定值,值为'code'
  34.         client_id           自己应用的API key
  35.         redirect_uri        授权回调地址。对于无server的应用,可将其值设为'oob',回调后会返回一个平台提供默认回调地址
  36.         scope               访问权限,即用户的实际授权列表,值为'basic', 'netdisk'二选一,含义分别为基础权限(访问您的个人资料等基础信息),百度网盘访问权限(在您的百度网盘创建文件夹并读写数据)
  37.         display             授权页的展示方式,默认为'page'
  38.         '''
  39.         get_code_url = 'https://openapi.baidu.com/oauth/2.0/authorize?response_type=code&client_id={}&redirect_uri=oob&scope=netdisk'.format(self.api_key)
  40.         code = input('请访问下面的链接:\n%s\n登录百度账号,并将授权码粘贴至此处,然后回车,完成授权:\n' % get_code_url)


  41.         '''
  42.         通过code,获取token
  43.         参数:
  44.         grant_type          固定值,值为'authorization_code'
  45.         code                上一步得到的授权码
  46.         client_id           应用的API KEY
  47.         client_secret       应用的SECRET KEY
  48.         redirect_uri        和上一步的redirect_uri相同
  49.         '''
  50.         get_token_url = 'https://openapi.baidu.com/oauth/2.0/token?grant_type=authorization_code'
  51.         params = {'code': code, 'client_id': api_key, 'client_secret': secret_key, 'redirect_uri': 'oob'}
  52.         res = requests.get(get_token_url, headers=self.headers, params = params)

  53.         try:
  54.             res_json = res.json()
  55.         except Exception as e:
  56.             print('请检查网络是否连通:%s' % e)
  57.             return False

  58.         if 'error' in res_json:
  59.             error = res_json['error']
  60.             print('获取token失败:%s' % error)
  61.             return False
  62.         elif 'access_token' in res_json and 'refresh_token' in res_json:
  63.             self.access_token = res_json['access_token']
  64.             self.refresh_token = res_json['refresh_token']
  65.             return True


  66.     def reflush_token(self):
  67.         '''
  68.         使用refresh_token,刷新token。
  69.         '''
  70.         reflush_token_url = 'https://openapi.baidu.com/oauth/2.0/token?grant_type=refresh_token'
  71.         #params = {'code': code, 'client_id': api_key, 'client_secret': secret_key, 'redirect_uri': 'oob'}
  72.         params = {'refresh_token': self.refresh_token, 'client_id': self.api_key, 'client_secret': self.secret_key}
  73.         res = requests.get(reflush_token_url, headers=self.headers, params = params)

  74.         try:
  75.             res_json = res.json()
  76.         except Exception as e:
  77.             print('请检查网络是否连通:%s' % e)
  78.             return False

  79.         if 'error' in res_json:
  80.             error = res_json['error']
  81.             print('刷新token失败:%s' % error)
  82.             return False
  83.         elif 'access_token' in res_json and 'refresh_token' in res_json:
  84.             self.access_token = res_json['access_token']
  85.             self.refresh_token = res_json['refresh_token']
  86.             return True


  87.     def init_token(self):
  88.         '''
  89.         如果存在配置文件且token存在时间少于27天,则直接从配置文件中读入token;
  90.         如果存在配置文件且token存在时间超过10个平年,则重新申请token;
  91.         如果存在配置文件且token存在时间大于27天,少于10个平年,则刷新token;
  92.         如果不存在配置文件,则申请token。
  93.         access_token的有效期是一个月,refresh_token的有效期是十年,access_token过期后,使用refresh_token刷新token即可
  94.         '''
  95.         conf = r'BaiduYunTransfer.conf'


  96.         if os.path.exists(conf):                               # 存在配置文件
  97.             with open(conf, 'r')as f:
  98.                 token = f.read()
  99.             lines = token.split('\n')
  100.             update_time = int(lines[5])
  101.             now_time = int(time.time())

  102.             if now_time - update_time < 27 * 24 * 60 * 60:      # token存在时间少于27天,则直接从配置文件中读入token
  103.                 self.access_token = lines[1]
  104.                 self.refresh_token = lines[3]
  105.                 print('已从配置文件中读入token')
  106.                 return True
  107.             elif now_time - update_time > 31536000 * 10:        # token存在时间超过10个平年,则重新申请token(10年后百度网盘还能不能用都不好说)
  108.                 self.apply_for_token()
  109.                 token = '[access_token]\n{}\n[refresh_token]\n{}\n[update_time]\n{}'.format(self.access_token, self.refresh_token, int(time.time()))
  110.                 with open(conf, 'w')as f:
  111.                     f.write(token)
  112.                 print('已重新申请token并将token写入配置文件中')
  113.             else:                                               # token存在时间大于27天,少于10个平年,则刷新token
  114.                 self.refresh_token = lines[3]
  115.                 self.reflush_token()
  116.                 token = '[access_token]\n{}\n[refresh_token]\n{}\n[update_time]\n{}'.format(self.access_token, self.refresh_token, int(time.time()))
  117.                 with open(conf, 'w')as f:
  118.                     f.write(token)
  119.                 print('已刷新token并将token写入配置文件中')
  120.                 return True
  121.         else:                                                   #未找到配置文件
  122.             self.apply_for_token()
  123.             token = '[access_token]\n{}\n[refresh_token]\n{}\n[update_time]\n{}'.format(self.access_token, self.refresh_token, int(time.time()))
  124.             with open(conf, 'w')as f:
  125.                 f.write(token)
  126.             print('已申请token并将token写入配置文件中')

  127.         print('asscee_token:', self.access_token)
  128.         print('refresh_token:', self.refresh_token)
  129.         return True


  130.     def get_surl(self):
  131.         '''
  132.         获取surl。举个例子:
  133.         short_link: https://pan.baidu.com/s/1LGDt_UQfdyQ9ga04bsnLKg
  134.         long_link: https://pan.baidu.com/share/init?surl=LGDt_UQfdyQ9ga04bsnLKg
  135.         surl: LGDt_UQfdyQ9ga04bsnLKg
  136.         '''
  137.         res = re.search(r'https://pan\.baidu\.com/share/init\?surl=([0-9a-zA-Z].+?), self.share_link)
  138.         if res:
  139.             print('long_link:', self.share_link)

  140.             self.surl = res.group(1)
  141.             print('surl:', self.surl)
  142.             return True
  143.         else:
  144.             print('short_link:', self.share_link)

  145.             res = requests.get(self.share_link, headers = self.headers)
  146.             reditList = res.history
  147.             link = reditList[len(reditList)-1].headers["location"]      # 302跳转的最后一跳的url
  148.             print('long_link:', link)

  149.             res = re.search(r'https://pan\.baidu\.com/share/init\?surl=([0-9a-zA-Z].+?), link)
  150.             if res:
  151.                 self.surl = res.group(1)
  152.                 print('surl:', self.surl)
  153.                 return True
  154.             else:
  155.                 print('获取surl失败')
  156.                 return False


  157.     def get_sekey(self):
  158.         '''
  159.         验证提取码是否正确,如果正确,得到一个与提取码有关的密钥串randsk(即后面获取文件目录信息和转存文件时需要用到的sekey)
  160.         详情参见:https://pan.baidu.com/union/document/openLink#%E9%99%84%E4%BB%B6%E5%AF%86%E7%A0%81%E9%AA%8C%E8%AF%81
  161.         '''
  162.         url = 'https://pan.baidu.com/rest/2.0/xpan/share?method=verify'
  163.         params = {'surl': self.surl}
  164.         data = {'pwd': self.password}
  165.         res = requests.post(url, headers = self.headers, params = params, data = data)

  166.         res_json = res.json()
  167.         errno = res_json['errno']
  168.         if errno == 0:
  169.             randsk = res_json['randsk']
  170.             self.sekey = urllib.parse.unquote(randsk, encoding='utf-8', errors='replace')       # 需要urldecode一下,不然%25会再次编码成%2525
  171.             print('sekey:', self.sekey)
  172.             return True
  173.         else:
  174.             error = {'105': '链接地址错误',
  175.                     '-12': '非会员用户达到转存文件数目上限',
  176.                     '-9': 'pwd错误',
  177.                     '2': '参数错误,或者判断是否有referer'}
  178.             error.update(self.universal_error_code)

  179.             if str(errno) in error:
  180.                 print('获取sekey失败,错误码:{},错误:{}'.format(errno, error[str(errno)]))
  181.             else:
  182.                 print('获取sekey失败,错误码:{},错误未知,请尝试查询https://pan.baidu.com/union/document/error#%E9%94%99%E8%AF%AF%E7%A0%81%E5%88%97%E8%A1%A8'.format(errno))

  183.             return False

  184.             # 提取码不是4位的时候,返回的errno是-12,含义是非会员用户达到转存文件数目上限,这是百度网盘的后端代码逻辑不正确,我也没办法。不过你闲的没事输入长度不是4位的提取码干嘛?


  185.     def get_shareid_and_uk_and_fsidlist(self):
  186.         '''
  187.         获取附件中的文件id列表,同时也会含有shareid和uk(userkey)
  188.         详情参见:https://pan.baidu.com/union/document/openLink#%E8%8E%B7%E5%8F%96%E9%99%84%E4%BB%B6%E4%B8%AD%E7%9A%84%E6%96%87%E4%BB%B6%E5%88%97%E8%A1%A8
  189.         shareid+uk和shorturl这两组参数只需要选择一组传入即可,这里我们不知道shareid和uk,所以传入shorturl,来获取文件列表信息和shareid和uk。
  190.         参数:
  191.         shareid             分享链接id
  192.         uk                  分享用户id(userkey)
  193.         shorturl            分享链接地址(就是前面提取出来的surl,如9PsW5sWFLdbR7eHZbnHelw,不是整个的绝对路径)
  194.         page                数据量大时,需分页
  195.         num                 每页个数,默认100
  196.         root                为1时,表示显示链接根目录下所有文件
  197.         fid                 文件夹ID,表示显示文件夹下的所有文件
  198.         sekey               附件链接密钥串,对应verify接口返回的randsk
  199.         '''
  200.         url = 'https://pan.baidu.com/rest/2.0/xpan/share?method=list'
  201.         params = {"shorturl": self.surl, "page":"1", "num":"100", "root":"1", "fid":"0", "sekey":self.sekey}
  202.         res = requests.get(url, headers=self.headers, params=params)
  203.         res_json = res.json()

  204.         res_json = res.json()
  205.         errno = res_json['errno']
  206.         if errno == 0:
  207.             self.shareid = res_json['share_id']
  208.             print('shareid:', self.shareid)

  209.             self.uk = res_json['uk']
  210.             print('uk:', self.uk)

  211.             fsidlist = res_json['list']
  212.             self.fsid_list = []
  213.             for fs in fsidlist:
  214.                 self.fsid_list.append(int(fs['fs_id']))
  215.             print('fsidlist:', self.fsid_list)

  216.             return True
  217.         else:
  218.             error = {'110': '有其他转存任务在进行',
  219.                     '105': '非会员用户达到转存文件数目上限',
  220.                     '-7': '达到高级会员转存上限'}
  221.             error.update(self.universal_error_code)

  222.             if str(errno) in error:
  223.                 print('获取shareid, uk, fsidlist失败,错误码:{},错误:{}'.format(errno, error[str(errno)]))
  224.             else:
  225.                 print('获取shareid, uk, fsidlist失败,错误码:{},错误未知,请尝试查询https://pan.baidu.com/union/document/error#%E9%94%99%E8%AF%AF%E7%A0%81%E5%88%97%E8%A1%A8'.format(errno))

  226.             return False

  227.     def file_transfer(self):
  228.         '''
  229.         附件文件转存
  230.         详情参见:https://pan.baidu.com/union/document/openLink#%E9%99%84%E4%BB%B6%E6%96%87%E4%BB%B6%E8%BD%AC%E5%AD%98
  231.         不过上面链接中的参数信息好像有些不太对,里面的示例的用法是对的。
  232.         GET参数:
  233.         access_token        前面拿到的access_token
  234.         shareid             分享链接id
  235.         from                分享用户id(userkey)
  236.         POST参数:
  237.         sekey               附件链接密钥串,对应verify接口返回的randsk
  238.         fsidlist            文件id列表,形如[557084550688759],[557084550688759, 557084550688788]
  239.         path                转存路径
  240.         '''
  241.         url = 'http://pan.baidu.com/rest/2.0/xpan/share?method=transfer'
  242.         params = {'access_token': self.access_token, 'shareid': self.shareid, 'from': self.uk,}
  243.         data = {'sekey': self.sekey, 'fsidlist': str(self.fsid_list), 'path': self.dir}
  244.         res = requests.post(url, headers = self.headers, params = params, data = data)

  245.         res_json = res.json()
  246.         errno = res_json['errno']
  247.         if errno == 0:
  248.             print('文件转存成功')
  249.             return True
  250.         else:
  251.             error = {'111': '有其他转存任务在进行',
  252.                     '120': '非会员用户达到转存文件数目上限',
  253.                     '130': '达到高级会员转存上限',
  254.                     '-33': '达到转存文件数目上限',
  255.                     '12': '批量操作失败',
  256.                     '-3': '转存文件不存在',
  257.                     '-9': '密码错误',
  258.                     '5': '分享文件夹等禁止文件'}
  259.             error.update(self.universal_error_code)

  260.             if str(errno) in error:
  261.                 print('文件转存失败,错误码:{},错误:{}\n返回JSON:{}'.format(errno, error[str(errno)], res_json))
  262.             else:
  263.                 print('文件转存失败,错误码:{},错误未知,请尝试查询https://pan.baidu.com/union/document/error#%E9%94%99%E8%AF%AF%E7%A0%81%E5%88%97%E8%A1%A8\n返回JSON:{}'.format(errno, res_json))

  264.             return False

  265.         # 转存路径不存在时返回errno=2, 参数错误,如:{"errno":2,"request_id":5234720642281834903}
  266.         # 自己转存自己分享的文件时返回errno=12,批量操作失败,如:{"errno":12,"task_id":0,"info":[{"path":"\/asm","errno":4,"fsid":95531336671296}]}
  267.         # 转存成功后再次转存到同一文件夹下时返回errno=12,批量操作失败,如:{"errno":12,"task_id":0,"info":[{"path":"\/doax","errno":-30,"fsid":557084550688759}]}


  268. if __name__ == '__main__':
  269.     api_key = 'GHkLa9AeMAwHK16C5suBKlk3'                                            # 按照https://pan.baidu.com/union/document/entrance#%E7%AE%80%E4%BB%8B 的指引,申请api_key和secret_key。
  270.     secret_key = '2ZRL3CXd6ocjtSwwAnX9ryYf4l85RYGm'                                 # 这里默认是我申请的api_key和secret_key,仅作测试使用。出于安全和QPS的考量,我推荐你去申请自己的api_key和secret_key。
  271.     share_link = 'https://pan.baidu.com/s/1LGDt_UQfdyQ9ga04bsnLKg'                  # 分享链接
  272.     #share_link = 'https://pan.baidu.com/share/init?surl=9PsW5sWFLdbR7eHZbnHelw'    # 分享链接,以上两种形式的链接都可以
  273.     password = 'w1yd'                                                               # 分享提取码
  274.     dir = '/转存测试'                                                               # 转存路径,根路径为/,记得提前在百度网盘内创建好目标转存目录
  275.     BaiduYunTransfer(api_key, secret_key, share_link, password, dir)
复制代码

最佳答案

查看完整内容

论坛有度盘操作模块吧..

回答提醒:如果本帖被关闭无法回复,您有更好的答案帮助楼主解决,请发表至 源码区 可获得加分喔。
友情提醒:本版被采纳的主题可在 申请荣誉值 页面申请荣誉值,获得 1点 荣誉值,荣誉值可兑换荣誉会员、终身vip用户组。
快捷通道:申请荣誉值无答案申请取消悬赏投诉有答案未采纳为最佳

结帖率:80% (68/85)

签到天数: 2 天

发表于 2021-3-19 15:45:05 | 显示全部楼层   河北省廊坊市
论坛有度盘操作模块吧..

评分

参与人数 1荣誉 +1 收起 理由
笨潴 + 1 热心帮助他人,荣誉+1,希望继续努力(*^__^*) 嘻嘻!

查看全部评分

回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则 致发广告者

发布主题 收藏帖子 返回列表

sitemap| 易语言源码| 易语言教程| 易语言论坛| 诚聘英才| 易语言模块| 手机版| 广告投放| 精易论坛
拒绝任何人以任何形式在本论坛发表与中华人民共和国法律相抵触的言论,本站内容均为会员发表,并不代表精易立场!
论坛帖子内容仅用于技术交流学习和研究的目的,严禁用于非法目的,否则造成一切后果自负!如帖子内容侵害到你的权益,请联系我们!
防范网络诈骗,远离网络犯罪 违法和不良信息举报电话0663-3422125,QQ: 800073686,邮箱:800073686@b.qq.com
Powered by Discuz! X3.4 揭阳市揭东区精易科技有限公司 ( 粤ICP备12094385号-1) 粤公网安备 44522102000125 增值电信业务经营许可证 粤B2-20192173

快速回复 返回顶部 返回列表