py_bilibili.py 36 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871
  1. # coding=utf-8
  2. # !/usr/bin/python
  3. import sys
  4. sys.path.append('..')
  5. from base.spider import Spider
  6. import json
  7. import requests
  8. from requests import session, utils
  9. import time
  10. import base64
  11. class Spider(Spider):
  12. def getName(self):
  13. return "哔哩哔哩"
  14. # 主页
  15. def homeContent(self, filter):
  16. result = {}
  17. cateManual = {
  18. "动态": "动态",
  19. "热门": "热门",
  20. "推荐": "推荐",
  21. "历史记录": "历史记录",
  22. # "稍后再看":"稍后再看", #意义不大,隐藏该项
  23. "收藏": "收藏",
  24. "动画": "1",
  25. "音乐": "3",
  26. "舞蹈": "129",
  27. "游戏": "4",
  28. "鬼畜": "119",
  29. "知识": "36",
  30. "科技": "188",
  31. "运动": "234",
  32. "生活": "160",
  33. "美食": "211",
  34. "动物": "217",
  35. "汽车": "223",
  36. "时尚": "155",
  37. "娱乐": "5",
  38. "影视": "181",
  39. "每周必看": "每周必看",
  40. "入站必刷": "入站必刷",
  41. "频道": "频道",
  42. # ————————以下可自定义关键字,结果以搜索方式展示————————
  43. }
  44. classes = []
  45. for k in cateManual:
  46. classes.append({
  47. 'type_name': k,
  48. 'type_id': cateManual[k]
  49. })
  50. result['class'] = classes
  51. if (filter):
  52. result['filters'] = self.config['filter']
  53. return result
  54. cookies = ''
  55. userid = ''
  56. def getCookie(self):
  57. import requests
  58. import http.cookies
  59. # --------↓↓↓↓↓↓↓------在下方双引号内填写-------↓↓↓↓↓↓↓--------
  60. raw_cookie_line = ""
  61. simple_cookie = http.cookies.SimpleCookie(raw_cookie_line)
  62. cookie_jar = requests.cookies.RequestsCookieJar()
  63. cookie_jar.update(simple_cookie)
  64. rsp = session()
  65. rsp.cookies = cookie_jar
  66. content = self.fetch("http://api.bilibili.com/x/web-interface/nav", cookies=rsp.cookies)
  67. res = json.loads(content.text)
  68. if res["code"] == 0:
  69. self.cookies = rsp.cookies
  70. self.userid = res["data"].get('mid')
  71. return cookie_jar
  72. def __init__(self):
  73. self.getCookie()
  74. url = 'https://api.bilibili.com/x/v3/fav/folder/created/list-all?up_mid=%s&jsonp=jsonp' % self.userid
  75. rsp = self.fetch(url, cookies=self.cookies)
  76. content = rsp.text
  77. jo = json.loads(content)
  78. fav_list = []
  79. if jo['code'] == 0:
  80. for fav in jo['data'].get('list'):
  81. fav_dict = {
  82. 'n': fav['title'].replace("<em class=\"keyword\">", "").replace("</em>", "").replace("&quot;",
  83. '"').strip(),
  84. 'v': fav['id']}
  85. fav_list.append(fav_dict)
  86. if self.config["filter"].get('收藏'):
  87. for i in self.config["filter"].get('收藏'):
  88. if i['key'] == 'mlid':
  89. i['value'] = fav_list
  90. def init(self, extend=""):
  91. print("============{0}============".format(extend))
  92. pass
  93. def isVideoFormat(self, url):
  94. pass
  95. def manualVideoCheck(self):
  96. pass
  97. # 将超过10000的数字换成成以万和亿为单位
  98. def zh(self, num):
  99. if int(num) >= 100000000:
  100. p = round(float(num) / float(100000000), 1)
  101. p = str(p) + '亿'
  102. else:
  103. if int(num) >= 10000:
  104. p = round(float(num) / float(10000), 1)
  105. p = str(p) + '万'
  106. else:
  107. p = str(num)
  108. return p
  109. # 将秒数转化为 时分秒的格式
  110. def second_to_time(self, a):
  111. if a < 3600:
  112. return time.strftime("%M:%S", time.gmtime(a))
  113. else:
  114. return time.strftime("%H:%M:%S", time.gmtime(a))
  115. # 字符串时分秒以及分秒形式转换成秒
  116. def str2sec(self, x):
  117. x = str(x)
  118. try:
  119. h, m, s = x.strip().split(':') # .split()函数将其通过':'分隔开,.strip()函数用来除去空格
  120. return int(h) * 3600 + int(m) * 60 + int(s) # int()函数转换成整数运算
  121. except:
  122. m, s = x.strip().split(':') # .split()函数将其通过':'分隔开,.strip()函数用来除去空格
  123. return int(m) * 60 + int(s) # int()函数转换成整数运算
  124. # 按时间过滤
  125. def filter_duration(self, vodlist, key):
  126. if key == '0':
  127. return vodlist
  128. else:
  129. vod_list_new = [i for i in vodlist if
  130. self.time_diff1[key][0] <= self.str2sec(str(i["vod_remarks"])) < self.time_diff1[key][1]]
  131. return vod_list_new
  132. time_diff1 = {'1': [0, 300],
  133. '2': [300, 900], '3': [900, 1800], '4': [1800, 3600],
  134. '5': [3600, 99999999999999999999999999999999]
  135. }
  136. time_diff = '0'
  137. def homeVideoContent(self):
  138. result = {}
  139. url = 'https://api.bilibili.com/x/web-interface/ranking/v2?rid=0&type=all'
  140. rsp = self.fetch(url, cookies=self.cookies)
  141. content = rsp.text
  142. jo = json.loads(content)
  143. if jo['code'] == 0:
  144. videos = []
  145. vodList = jo['data']['list']
  146. for vod in vodList:
  147. aid = str(vod['aid']).strip()
  148. title = vod['title'].strip().replace("<em class=\"keyword\">", "").replace("</em>", "")
  149. img = vod['pic'].strip()
  150. # view = "▶" + self.zh(vod['stat']['view']) + ' 🕓' # 标签上加入播放量
  151. remark = str(self.second_to_time(vod['duration'])).strip()
  152. videos.append({
  153. "vod_id": aid,
  154. "vod_name": title,
  155. "vod_pic": img,
  156. "vod_remarks": remark
  157. })
  158. result = {
  159. 'list': videos
  160. }
  161. return result
  162. dynamic_offset = ''
  163. def get_dynamic(self, pg):
  164. result = {}
  165. if str(pg) == '1':
  166. url = 'https://api.bilibili.com/x/polymer/web-dynamic/v1/feed/all?timezone_offset=-480&type=all&page=%s' % pg
  167. else:
  168. # print('偏移',self.dynamic_offset)
  169. url = 'https://api.bilibili.com/x/polymer/web-dynamic/v1/feed/all?timezone_offset=-480&type=all&offset=%s&page=%s' % (self.dynamic_offset, pg)
  170. rsp = self.fetch(url, cookies=self.cookies)
  171. content = rsp.text
  172. jo = json.loads(content)
  173. if jo['code'] == 0:
  174. self.dynamic_offset = jo['data'].get('offset')
  175. videos = []
  176. vodList = jo['data']['items']
  177. for vod in vodList:
  178. if vod['type'] == 'DYNAMIC_TYPE_AV':
  179. up = vod['modules']["module_author"]['name']
  180. ivod = vod['modules']['module_dynamic']['major']['archive']
  181. aid = str(ivod['aid']).strip()
  182. title = ivod['title'].strip().replace("<em class=\"keyword\">", "").replace("</em>", "")
  183. img = ivod['cover'].strip()
  184. # remark = str(ivod['duration_text']).strip()
  185. remark = str(self.second_to_time(self.str2sec(ivod['duration_text']))).strip() + ' ' + str(
  186. up).strip() # 显示分钟数+up主名字
  187. videos.append({
  188. "vod_id": aid,
  189. "vod_name": title,
  190. "vod_pic": img,
  191. "vod_remarks": remark
  192. })
  193. result['list'] = videos
  194. result['page'] = pg
  195. result['pagecount'] = 9999
  196. result['limit'] = 90
  197. result['total'] = 999999
  198. return result
  199. def get_hot(self, pg):
  200. result = {}
  201. url = 'https://api.bilibili.com/x/web-interface/popular?ps=20&pn={0}'.format(pg)
  202. rsp = self.fetch(url, cookies=self.cookies)
  203. content = rsp.text
  204. jo = json.loads(content)
  205. if jo['code'] == 0:
  206. videos = []
  207. vodList = jo['data']['list']
  208. for vod in vodList:
  209. aid = str(vod['aid']).strip()
  210. title = vod['title'].strip().replace("<em class=\"keyword\">", "").replace("</em>", "")
  211. img = vod['pic'].strip()
  212. remark = str(self.second_to_time(vod['duration'])).strip()
  213. videos.append({
  214. "vod_id": aid,
  215. "vod_name": title,
  216. "vod_pic": img,
  217. "vod_remarks": remark
  218. })
  219. result['list'] = videos
  220. result['page'] = pg
  221. result['pagecount'] = 9999
  222. result['limit'] = 90
  223. result['total'] = 999999
  224. return result
  225. def get_rcmd(self, pg):
  226. result = {}
  227. url = 'https://api.bilibili.com/x/web-interface/index/top/feed/rcmd?y_num={0}&fresh_type=3&feed_version=SEO_VIDEO&fresh_idx_1h=1&fetch_row=1&fresh_idx=1&brush=0&homepage_ver=1&ps=20'.format(
  228. pg)
  229. rsp = self.fetch(url, cookies=self.cookies)
  230. content = rsp.text
  231. jo = json.loads(content)
  232. if jo['code'] == 0:
  233. videos = []
  234. vodList = jo['data']['item']
  235. for vod in vodList:
  236. if vod['duration'] > 0:
  237. aid = str(vod['id']).strip()
  238. title = vod['title'].strip().replace("<em class=\"keyword\">", "").replace("</em>", "")
  239. img = vod['pic'].strip()
  240. remark = str(self.second_to_time(vod['duration'])).strip()
  241. videos.append({
  242. "vod_id": aid,
  243. "vod_name": title,
  244. "vod_pic": img,
  245. "vod_remarks": remark
  246. })
  247. result['list'] = videos
  248. result['page'] = pg
  249. result['pagecount'] = 9999
  250. result['limit'] = 90
  251. result['total'] = 999999
  252. return result
  253. def get_rank(self):
  254. result = {}
  255. url = 'https://api.bilibili.com/x/web-interface/ranking/v2?rid=0&type=all'
  256. rsp = self.fetch(url, cookies=self.cookies)
  257. content = rsp.text
  258. jo = json.loads(content)
  259. if jo['code'] == 0:
  260. videos = []
  261. vodList = jo['data']['list']
  262. for vod in vodList:
  263. aid = str(vod['aid']).strip()
  264. title = vod['title'].strip().replace("<em class=\"keyword\">", "").replace("</em>", "")
  265. img = vod['pic'].strip()
  266. remark = str(self.second_to_time(vod['duration'])).strip()
  267. videos.append({
  268. "vod_id": aid,
  269. "vod_name": title,
  270. "vod_pic": img,
  271. "vod_remarks": remark
  272. })
  273. result['list'] = videos
  274. result['page'] = 1
  275. result['pagecount'] = 1
  276. result['limit'] = 90
  277. result['total'] = 999999
  278. return result
  279. def get_history(self, pg):
  280. result = {}
  281. url = 'https://api.bilibili.com/x/v2/history?pn=%s' % pg
  282. rsp = self.fetch(url, cookies=self.cookies)
  283. content = rsp.text
  284. jo = json.loads(content) # 解析api接口,转化成json数据对象
  285. if jo['code'] == 0:
  286. videos = []
  287. vodList = jo['data']
  288. for vod in vodList:
  289. if vod['duration'] > 0: # 筛选掉非视频的历史记录
  290. aid = str(vod["aid"]).strip()
  291. title = vod["title"].replace("<em class=\"keyword\">", "").replace("</em>", "").replace("&quot;",
  292. '"')
  293. img = vod["pic"].strip()
  294. # 获取已观看时间
  295. if str(vod['progress']) == '-1':
  296. process = str(self.second_to_time(vod['duration'])).strip()
  297. else:
  298. process = str(self.second_to_time(vod['progress'])).strip()
  299. # 获取视频总时长
  300. total_time = str(self.second_to_time(vod['duration'])).strip()
  301. # 组合 已观看时间 / 总时长 ,赋值给 remark
  302. remark = process + ' / ' + total_time
  303. videos.append({
  304. "vod_id": aid,
  305. "vod_name": title,
  306. "vod_pic": img,
  307. "vod_remarks": remark
  308. })
  309. result['list'] = videos
  310. result['page'] = pg
  311. result['pagecount'] = 9999
  312. result['limit'] = 90
  313. result['total'] = 999999
  314. return result
  315. def get_fav(self, pg, order, extend):
  316. mlid = ''
  317. fav_config = self.config["filter"].get('收藏')
  318. # 默认显示第一个收藏内容
  319. if fav_config:
  320. for i in fav_config:
  321. if i['key'] == 'mlid':
  322. if len(i['value']) > 0:
  323. mlid = i['value'][0]['v']
  324. # print(self.config["filter"].get('收藏'))
  325. if 'mlid' in extend:
  326. mlid = extend['mlid']
  327. if mlid:
  328. return self.get_fav_detail(pg=pg, mlid=mlid, order=order)
  329. else:
  330. return {}
  331. def get_fav_detail(self, pg, mlid, order):
  332. result = {}
  333. url = 'https://api.bilibili.com/x/v3/fav/resource/list?media_id=%s&order=%s&pn=%s&ps=20&platform=web&type=0' % (mlid, order, pg)
  334. rsp = self.fetch(url, cookies=self.cookies)
  335. content = rsp.text
  336. jo = json.loads(content)
  337. if jo['code'] == 0:
  338. videos = []
  339. vodList = jo['data']['medias']
  340. for vod in vodList:
  341. # print(vod)
  342. # 只展示类型为 视频的条目
  343. # 过滤去掉收藏中的 已失效视频;如果不喜欢可以去掉这个 if条件
  344. if vod.get('type') in [2] and vod.get('title') != '已失效视频':
  345. aid = str(vod['id']).strip()
  346. title = vod['title'].replace("<em class=\"keyword\">", "").replace("</em>", "").replace("&quot;",
  347. '"')
  348. img = vod['cover'].strip()
  349. remark = str(self.second_to_time(vod['duration'])).strip()
  350. videos.append({
  351. "vod_id": aid,
  352. "vod_name": title,
  353. "vod_pic": img,
  354. "vod_remarks": remark
  355. })
  356. # videos=self.filter_duration(videos, duration_diff)
  357. result['list'] = videos
  358. result['page'] = pg
  359. result['pagecount'] = 9999
  360. result['limit'] = 90
  361. result['total'] = 999999
  362. return result
  363. def get_zone(self, tid):
  364. result = {}
  365. url = 'https://api.bilibili.com/x/web-interface/ranking/v2?rid={0}&type=all'.format(tid)
  366. rsp = self.fetch(url, cookies=self.cookies)
  367. content = rsp.text
  368. jo = json.loads(content)
  369. if jo['code'] == 0:
  370. videos = []
  371. vodList = jo['data']['list']
  372. for vod in vodList:
  373. aid = str(vod['aid']).strip()
  374. title = vod['title'].strip().replace("<em class=\"keyword\">", "").replace("</em>", "")
  375. img = vod['pic'].strip()
  376. remark = str(self.second_to_time(vod['duration'])).strip()
  377. videos.append({
  378. "vod_id": aid,
  379. "vod_name": title,
  380. "vod_pic": img,
  381. "vod_remarks": remark
  382. })
  383. result['list'] = videos
  384. result['page'] = 1
  385. result['pagecount'] = 1
  386. result['limit'] = 90
  387. result['total'] = 999999
  388. return result
  389. def get_weekly(self):
  390. result = {}
  391. url1 = 'https://api.bilibili.com/x/web-interface/popular/series/list'
  392. rsp1 = self.fetch(url1, cookies=self.cookies)
  393. content1 = rsp1.text
  394. jo1 = json.loads(content1)
  395. number = jo1['data']['list'][0]['number']
  396. url = 'https://api.bilibili.com/x/web-interface/popular/series/one?number=' + str(number)
  397. rsp = self.fetch(url, cookies=self.cookies)
  398. content = rsp.text
  399. jo = json.loads(content)
  400. if jo['code'] == 0:
  401. videos = []
  402. vodList = jo['data']['list']
  403. for vod in vodList:
  404. aid = str(vod['aid']).strip()
  405. title = vod['title'].strip()
  406. img = vod['pic'].strip()
  407. remark = str(self.second_to_time(vod['duration'])).strip()
  408. videos.append({
  409. "vod_id": aid,
  410. "vod_name": title,
  411. "vod_pic": img,
  412. "vod_remarks": remark
  413. })
  414. result['list'] = videos
  415. result['page'] = 1
  416. result['pagecount'] = 1
  417. result['limit'] = 90
  418. result['total'] = 999999
  419. return result
  420. def get_must_watch(self):
  421. result = {}
  422. url = 'https://api.bilibili.com/x/web-interface/popular/precious?page_size=100&page=1'
  423. rsp = self.fetch(url, cookies=self.cookies)
  424. content = rsp.text
  425. jo = json.loads(content)
  426. if jo['code'] == 0:
  427. videos = []
  428. vodList = jo['data']['list']
  429. for vod in vodList:
  430. aid = str(vod['aid']).strip()
  431. title = vod['title'].strip()
  432. img = vod['pic'].strip()
  433. remark = str(self.second_to_time(vod['duration'])).strip()
  434. videos.append({
  435. "vod_id": aid,
  436. "vod_name": title,
  437. "vod_pic": img,
  438. "vod_remarks": remark
  439. })
  440. result['list'] = videos
  441. result['page'] = 1
  442. result['pagecount'] = 1
  443. result['limit'] = 90
  444. result['total'] = 999999
  445. return result
  446. def get_toview(self, pg):
  447. result = {}
  448. url = 'https://api.bilibili.com/x/v2/history/toview'
  449. rsp = self.fetch(url, cookies=self.cookies)
  450. content = rsp.text
  451. jo = json.loads(content) # 解析api接口,转化成json数据对象
  452. if jo['code'] == 0:
  453. videos = []
  454. vodList = jo['data']['list']
  455. for vod in vodList:
  456. if vod['duration'] > 0:
  457. aid = str(vod["aid"]).strip()
  458. title = vod["title"].replace("<em class=\"keyword\">", "").replace("</em>", "").replace("&quot;",
  459. '"')
  460. img = vod["pic"].strip()
  461. if str(vod['progress']) == '-1':
  462. process = str(self.second_to_time(vod['duration'])).strip()
  463. else:
  464. process = str(self.second_to_time(vod['progress'])).strip()
  465. # 获取视频总时长
  466. total_time = str(self.second_to_time(vod['duration'])).strip()
  467. # 组合 已观看时间 / 总时长 ,赋值给 remark
  468. remark = process + ' / ' + total_time
  469. videos.append({
  470. "vod_id": aid + '&toview',
  471. "vod_name": title,
  472. "vod_pic": img,
  473. "vod_remarks": remark
  474. })
  475. result['list'] = videos
  476. result['page'] = 1
  477. result['pagecount'] = 1
  478. result['limit'] = 90
  479. result['total'] = 999999
  480. return result
  481. chanel_offset = ''
  482. def get_channel(self, pg, cid, extend, order, duration_diff):
  483. result = {}
  484. url = 'https://api.bilibili.com/x/web-interface/search/type?search_type=video&keyword={0}&page={1}&duration={2}&order={3}'.format(
  485. cid, pg, duration_diff, order)
  486. rsp = self.fetch(url, cookies=self.cookies)
  487. content = rsp.text
  488. jo = json.loads(content)
  489. if jo.get('code') == 0:
  490. videos = []
  491. vodList = jo['data']['result']
  492. for vod in vodList:
  493. aid = str(vod['aid']).strip()
  494. title = vod['title'].replace("<em class=\"keyword\">", "").replace("</em>", "").replace("&quot;", '"')
  495. img = 'https:' + vod['pic'].strip()
  496. remark = str(self.second_to_time(self.str2sec(vod['duration']))).strip()
  497. videos.append({
  498. "vod_id": aid,
  499. "vod_name": title,
  500. "vod_pic": img,
  501. "vod_remarks": remark
  502. })
  503. # videos=self.filter_duration(videos, duration_diff)
  504. result['list'] = videos
  505. result['page'] = pg
  506. result['pagecount'] = 9999
  507. result['limit'] = 90
  508. result['total'] = 999999
  509. return result
  510. def categoryContent(self, tid, pg, filter, extend):
  511. result = {}
  512. if len(self.cookies) <= 0:
  513. self.getCookie()
  514. if tid == "动态":
  515. return self.get_dynamic(pg=pg)
  516. elif tid == "热门":
  517. return self.get_hot(pg=pg)
  518. elif tid == '推荐':
  519. return self.get_rcmd(pg=pg)
  520. elif tid == '历史记录':
  521. return self.get_history(pg=pg)
  522. elif tid == "每周必看":
  523. return self.get_weekly()
  524. elif tid == "入站必刷":
  525. return self.get_must_watch()
  526. elif tid == '稍后再看':
  527. return self.get_toview(pg=pg)
  528. elif tid in ("1", "3", "129", "4", "119", "36", "188", "234", "160", "211", "217", "223", "155", "5", "181"):
  529. return self.get_zone(tid=tid)
  530. elif tid == "收藏":
  531. order = 'mtime'
  532. if 'order' in extend:
  533. order = extend['order']
  534. return self.get_fav(pg=pg, order=order, extend=extend)
  535. elif tid == '频道':
  536. cid = '搞笑'
  537. if 'cid' in extend:
  538. cid = extend['cid']
  539. duration_diff = '0'
  540. if 'duration' in extend:
  541. duration_diff = extend['duration']
  542. order = 'totalrank'
  543. if 'order' in extend:
  544. order = extend['order']
  545. return self.get_channel(pg=pg, cid=cid, extend=extend, order=order, duration_diff=duration_diff)
  546. else:
  547. duration_diff = '0'
  548. if 'duration' in extend:
  549. duration_diff = extend['duration']
  550. order = 'totalrank'
  551. if 'order' in extend:
  552. order = extend['order']
  553. url = 'https://api.bilibili.com/x/web-interface/search/type?search_type=video&keyword={0}&page={1}&duration={2}&order={3}'.format(
  554. tid, pg, duration_diff, order)
  555. rsp = self.fetch(url, cookies=self.cookies)
  556. content = rsp.text
  557. jo = json.loads(content)
  558. if jo.get('code') == 0:
  559. videos = []
  560. vodList = jo['data']['result']
  561. for vod in vodList:
  562. aid = str(vod['aid']).strip()
  563. title = vod['title'].replace("<em class=\"keyword\">", "").replace("</em>", "").replace("&quot;",
  564. '"')
  565. img = 'https:' + vod['pic'].strip()
  566. # remark = str(vod['duration']).strip()
  567. remark = str(self.second_to_time(self.str2sec(vod['duration']))).strip()
  568. videos.append({
  569. "vod_id": aid,
  570. "vod_name": title,
  571. "vod_pic": img,
  572. "vod_remarks": remark
  573. })
  574. # videos=self.filter_duration(videos, duration_diff)
  575. result['list'] = videos
  576. result['page'] = pg
  577. result['pagecount'] = 9999
  578. result['limit'] = 90
  579. result['total'] = 999999
  580. return result
  581. def cleanSpace(self, str):
  582. return str.replace('\n', '').replace('\t', '').replace('\r', '').replace(' ', '')
  583. def detailContent(self, array):
  584. aid = array[0]
  585. url = "https://api.bilibili.com/x/web-interface/view?aid={0}".format(aid)
  586. rsp = self.fetch(url, headers=self.header, cookies=self.cookies)
  587. jRoot = json.loads(rsp.text)
  588. jo = jRoot['data']
  589. title = jo['title'].replace("<em class=\"keyword\">", "").replace("</em>", "")
  590. pic = jo['pic']
  591. desc = jo['desc']
  592. typeName = jo['tname']
  593. date = time.strftime("%Y%m%d", time.localtime(jo['pubdate'])) # 投稿时间本地年月日表示
  594. stat = jo['stat']
  595. # 演员项展示视频状态,包括以下内容:
  596. status = "播放: " + self.zh(stat['view']) + " 弹幕: " + self.zh(stat['danmaku']) + " 点赞: " + self.zh(stat['like']) + " 收藏: " + self.zh(stat['favorite']) + " 投币: " + self.zh(stat['coin'])
  597. remark = str(jo['duration']).strip()
  598. vod = {
  599. "vod_id": aid,
  600. "vod_name": '[' + jo['owner']['name'] + "]" + title,
  601. "vod_pic": pic,
  602. "type_name": typeName,
  603. "vod_year": date,
  604. "vod_area": "bilidanmu",
  605. "vod_remarks": remark, # 不会显示
  606. 'vod_tags': 'mv', # 不会显示
  607. "vod_actor": status,
  608. "vod_director": jo['owner']['name'],
  609. "vod_content": desc
  610. }
  611. ja = jo['pages']
  612. playUrl = ''
  613. for tmpJo in ja:
  614. cid = tmpJo['cid']
  615. part = tmpJo['part'].replace("#", "-")
  616. playUrl = playUrl + '{0}${1}_{2}#'.format(part, aid, cid)
  617. vod['vod_play_from'] = 'B站'
  618. vod['vod_play_url'] = playUrl
  619. result = {
  620. 'list': [
  621. vod
  622. ]
  623. }
  624. return result
  625. def searchContent(self, key, quick):
  626. url = 'https://api.bilibili.com/x/web-interface/search/type?search_type=video&keyword={0}&page=1'.format(key)
  627. rsp = self.fetch(url, cookies=self.cookies, headers=self.header)
  628. content = rsp.text
  629. jo = json.loads(content)
  630. if jo['code'] != 0:
  631. rspRetry = self.fetch(url, cookies=self.cookies, headers=self.header)
  632. content = rspRetry.text
  633. jo = json.loads(content)
  634. videos = []
  635. vodList = jo['data']['result']
  636. for vod in vodList:
  637. aid = str(vod['aid']).strip()
  638. title = '[' + key + ']' + vod['title'].replace("<em class=\"keyword\">", "").replace("</em>", "").replace("&quot;", '"')
  639. img = 'https:' + vod['pic'].strip()
  640. remark = str(self.second_to_time(self.str2sec(vod['duration']))).strip()
  641. videos.append({
  642. "vod_id": aid,
  643. "vod_name": title,
  644. "vod_pic": img,
  645. "vod_remarks": remark
  646. })
  647. result = {
  648. 'list': videos
  649. }
  650. return result
  651. def playerContent(self, flag, id, vipFlags):
  652. result = {}
  653. ids = id.split("_")
  654. if len(ids) < 2:
  655. return result
  656. url = 'https://api.bilibili.com:443/x/player/playurl?avid={0}&cid={1}&qn=116'.format(ids[0], ids[1])
  657. if len(self.cookies) <= 0:
  658. self.getCookie()
  659. rsp = self.fetch(url, cookies=self.cookies)
  660. jRoot = json.loads(rsp.text)
  661. jo = jRoot['data']
  662. ja = jo['durl']
  663. maxSize = -1
  664. position = -1
  665. for i in range(len(ja)):
  666. tmpJo = ja[i]
  667. if maxSize < int(tmpJo['size']):
  668. maxSize = int(tmpJo['size'])
  669. position = i
  670. url = ''
  671. if len(ja) > 0:
  672. if position == -1:
  673. position = 0
  674. url = ja[position]['url']
  675. result["parse"] = 0
  676. result["playUrl"] = ''
  677. result["url"] = url
  678. result["header"] = {
  679. "Referer": "https://www.bilibili.com",
  680. "User-Agent": 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36'
  681. }
  682. result["contentType"] = 'video/x-flv'
  683. return result
  684. config = {
  685. "player": {},
  686. "filter": {
  687. "收藏": [{
  688. "key": "order",
  689. "name": "排序",
  690. "value": [
  691. {
  692. "n": "收藏时间",
  693. "v": "mtime"
  694. },
  695. {
  696. "n": "播放量",
  697. "v": "view"
  698. },
  699. {
  700. "n": "投稿时间",
  701. "v": "pubtime"
  702. }
  703. ]
  704. },
  705. {
  706. "key": "mlid",
  707. "name": "收藏分区",
  708. "value": [
  709. ]
  710. }],
  711. "频道": [{
  712. "key": "order",
  713. "name": "排序",
  714. "value": [
  715. {
  716. "n": "综合排序",
  717. "v": "totalrank"
  718. },
  719. {
  720. "n": "最新发布",
  721. "v": "pubdate"
  722. },
  723. {
  724. "n": "最多点击",
  725. "v": "click"
  726. },
  727. {
  728. "n": "最多收藏",
  729. "v": "stow"
  730. },
  731. {
  732. "n": "最多弹幕",
  733. "v": "dm"
  734. },
  735. ]
  736. },
  737. {
  738. "key": "duration",
  739. "name": "时长",
  740. "value": [{
  741. "n": "全部",
  742. "v": "0"
  743. },
  744. {
  745. "n": "60分钟以上",
  746. "v": "4"
  747. },
  748. {
  749. "n": "30~60分钟",
  750. "v": "3"
  751. },
  752. {
  753. "n": "5~30分钟",
  754. "v": "2"
  755. },
  756. {
  757. "n": "5分钟以下",
  758. "v": "1"
  759. }
  760. ]
  761. }, {"key": "cid", "name": "分类",
  762. "value": [{'n': '搞笑', 'v': '搞笑'}, {'n': '美食', 'v': '美食'}, {'n': '鬼畜', 'v': '鬼畜'},
  763. {'n': '美妆', 'v': '美妆'}, {'n': 'mmd', 'v': 'mmd'}, {'n': '科普', 'v': '科普'},
  764. {'n': 'COSPLAY', 'v': 'COSPLAY'}, {'n': '漫展', 'v': '漫展'}, {'n': 'MAD', 'v': 'MAD'},
  765. {'n': '手书', 'v': '手书'}, {'n': '穿搭', 'v': '穿搭'}, {'n': '发型', 'v': '发型'},
  766. {'n': '化妆教程', 'v': '化妆教程'}, {'n': '电音', 'v': '电音'}, {'n': '欧美音乐', 'v': '欧美音乐'},
  767. {'n': '中文翻唱', 'v': '中文翻唱'}, {'n': '洛天依', 'v': '洛天依'}, {'n': '翻唱', 'v': '翻唱'},
  768. {'n': '日文翻唱', 'v': '日文翻唱'}, {'n': '科普', 'v': '科普'}, {'n': '技术宅', 'v': '技术宅'},
  769. {'n': '历史', 'v': '历史'}, {'n': '科学', 'v': '科学'}, {'n': '人文', 'v': '人文'},
  770. {'n': '科幻', 'v': '科幻'}, {'n': '手机', 'v': '手机'}, {'n': '手机评测', 'v': '手机评测'},
  771. {'n': '电脑', 'v': '电脑'}, {'n': '摄影', 'v': '摄影'}, {'n': '笔记本', 'v': '笔记本'},
  772. {'n': '装机', 'v': '装机'}, {'n': '课堂教育', 'v': '课堂教育'}, {'n': '公开课', 'v': '公开课'},
  773. {'n': '演讲', 'v': '演讲'}, {'n': 'PS教程', 'v': 'PS教程'}, {'n': '编程', 'v': '编程'},
  774. {'n': '英语学习', 'v': '英语学习'}, {'n': '喵星人', 'v': '喵星人'}, {'n': '萌宠', 'v': '萌宠'},
  775. {'n': '汪星人', 'v': '汪星人'}, {'n': '大熊猫', 'v': '大熊猫'}, {'n': '柴犬', 'v': '柴犬'},
  776. {'n': '田园犬', 'v': '田园犬'}, {'n': '吱星人', 'v': '吱星人'}, {'n': '美食', 'v': '美食'},
  777. {'n': '甜点', 'v': '甜点'}, {'n': '吃货', 'v': '吃货'}, {'n': '厨艺', 'v': '厨艺'},
  778. {'n': '烘焙', 'v': '烘焙'}, {'n': '街头美食', 'v': '街头美食'},
  779. {'n': 'A.I.Channel', 'v': 'A.I.Channel'}, {'n': '虚拟UP主', 'v': '虚拟UP主'},
  780. {'n': '神楽めあ', 'v': '神楽めあ'}, {'n': '白上吹雪', 'v': '白上吹雪'}, {'n': '婺源', 'v': '婺源'},
  781. {'n': 'hololive', 'v': 'hololive'}, {'n': 'EXO', 'v': 'EXO'},
  782. {'n': '防弹少年团', 'v': '防弹少年团'}, {'n': '肖战', 'v': '肖战'}, {'n': '王一博', 'v': '王一博'},
  783. {'n': '易烊千玺', 'v': '易烊千玺'}, {'n': '赵今麦', 'v': '赵今麦'}, {'n': '宅舞', 'v': '宅舞'},
  784. {'n': '街舞', 'v': '街舞'}, {'n': '舞蹈教学', 'v': '舞蹈教学'}, {'n': '明星舞蹈', 'v': '明星舞蹈'},
  785. {'n': '韩舞', 'v': '韩舞'}, {'n': '古典舞', 'v': '古典舞'}, {'n': '旅游', 'v': '旅游'},
  786. {'n': '绘画', 'v': '绘画'}, {'n': '手工', 'v': '手工'}, {'n': 'vlog', 'v': 'vlog'},
  787. {'n': 'DIY', 'v': 'DIY'}, {'n': '手绘', 'v': '手绘'}, {'n': '综艺', 'v': '综艺'},
  788. {'n': '国家宝藏', 'v': '国家宝藏'}, {'n': '脱口秀', 'v': '脱口秀'}, {'n': '日本综艺', 'v': '日本综艺'},
  789. {'n': '国内综艺', 'v': '国内综艺'}, {'n': '人类观察', 'v': '人类观察'}, {'n': '影评', 'v': '影评'},
  790. {'n': '电影解说', 'v': '电影解说'}, {'n': '影视混剪', 'v': '影视混剪'}, {'n': '影视剪辑', 'v': '影视剪辑'},
  791. {'n': '漫威', 'v': '漫威'}, {'n': '超级英雄', 'v': '超级英雄'}, {'n': '影视混剪', 'v': '影视混剪'},
  792. {'n': '影视剪辑', 'v': '影视剪辑'},
  793. {'n': '诸葛亮', 'v': '诸葛亮'}, {'n': '韩剧', 'v': '韩剧'}, {'n': '王司徒', 'v': '王司徒'},
  794. {'n': '泰剧', 'v': '泰剧'},
  795. {'n': '郭德纲', 'v': '郭德纲'}, {'n': '相声', 'v': '相声'}, {'n': '张云雷', 'v': '张云雷'},
  796. {'n': '秦霄贤', 'v': '秦霄贤'}, {'n': '孟鹤堂', 'v': '孟鹤堂'}, {'n': '岳云鹏', 'v': '岳云鹏'},
  797. {'n': '假面骑士', 'v': '假面骑士'}, {'n': '特摄', 'v': '特摄'}, {'n': '奥特曼', 'v': '奥特曼'},
  798. {'n': '迪迦奥特曼', 'v': '迪迦奥特曼'}, {'n': '超级战队', 'v': '超级战队'}, {'n': '铠甲勇士', 'v': '铠甲勇士'},
  799. {'n': '健身', 'v': '健身'}, {'n': '篮球', 'v': '篮球'}, {'n': '体育', 'v': '体育'},
  800. {'n': '帕梅拉', 'v': '帕梅拉'}, {'n': '极限运动', 'v': '极限运动'}, {'n': '足球', 'v': '足球'},
  801. {'n': '星海', 'v': '星海'}, {'n': '张召忠', 'v': '张召忠'}, {'n': '航母', 'v': '航母'},
  802. {'n': '航天', 'v': '航天'}, {'n': '导弹', 'v': '导弹'}, {'n': '战斗机', 'v': '战斗机'}]
  803. }
  804. ],
  805. }
  806. }
  807. header = {
  808. "Referer": "https://www.bilibili.com",
  809. "User-Agent": 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36'
  810. }
  811. def localProxy(self, param):
  812. return [200, "video/MP2T", action, ""]