py_bilizb.py 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675
  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. class Spider(Spider):
  8. def getDependence(self):
  9. return ['py_bilibili']
  10. def getName(self):
  11. return "哔哩直播"
  12. # 主页
  13. def homeContent(self, filter):
  14. result = {}
  15. cateManual = {
  16. "我的关注": "我的关注",
  17. "观看记录": "观看记录",
  18. "推荐": "推荐",
  19. "热门": "热门",
  20. "网游": "2",
  21. "手游": "3",
  22. "单机": "6",
  23. "娱乐": "1",
  24. "生活": "10",
  25. "知识": "11",
  26. "赛事": "13",
  27. "电台": "5",
  28. "虚拟": "9",
  29. }
  30. classes = []
  31. for k in cateManual:
  32. classes.append({
  33. 'type_name': k,
  34. 'type_id': cateManual[k]
  35. })
  36. result['class'] = classes
  37. if (filter):
  38. result['filters'] = self.config['filter']
  39. return result
  40. # 用户cookies
  41. cookies = ''
  42. def getCookie(self):
  43. self.cookies = self.bilibili.getCookie()
  44. return self.cookies
  45. def init(self, extend=""):
  46. self.bilibili = extend[0]
  47. print("============{0}============".format(extend))
  48. pass
  49. def isVideoFormat(self, url):
  50. pass
  51. def manualVideoCheck(self):
  52. pass
  53. # 将超过10000的数字换成成以万和亿为单位
  54. def zh(self, num):
  55. if int(num) >= 100000000:
  56. p = round(float(num) / float(100000000), 1)
  57. p = str(p) + '亿'
  58. else:
  59. if int(num) >= 10000:
  60. p = round(float(num) / float(10000), 1)
  61. p = str(p) + '万'
  62. else:
  63. p = str(num)
  64. return p
  65. uname = ''
  66. def get_live_userInfo(self, uid):
  67. url = 'https://api.live.bilibili.com/live_user/v1/Master/info?uid=%s' % uid
  68. rsp = self.fetch(url, headers=self.header, cookies=self.cookies)
  69. content = rsp.text
  70. jo = json.loads(content)
  71. if jo['code'] == 0:
  72. return jo['data']["info"]["uname"]
  73. def homeVideoContent(self,):
  74. result = {}
  75. videos = self.get_hot(1)['list'][0:3]
  76. result['list'] = videos
  77. return result
  78. def get_recommend(self, pg):
  79. result = {}
  80. url = 'https://api.live.bilibili.com/xlive/web-interface/v1/webMain/getList?platform=web&page=%s' % pg
  81. rsp = self.fetch(url, headers=self.header, cookies=self.cookies)
  82. content = rsp.text
  83. jo = json.loads(content)
  84. if jo['code'] == 0:
  85. videos = []
  86. vodList = jo['data']['recommend_room_list']
  87. for vod in vodList:
  88. aid = str(vod['roomid']).strip()
  89. title = vod['title'].replace("<em class=\"keyword\">", "").replace("</em>", "").replace("&quot;", '"')
  90. img = vod['keyframe'].strip()
  91. remark = vod['watched_show']['text_small'].strip() + " " + vod['uname'].strip()
  92. videos.append({
  93. "vod_id": aid + '&live',
  94. "vod_name": title,
  95. "vod_pic": img + '@672w_378h_1c.jpg',
  96. "vod_remarks": remark
  97. })
  98. result['list'] = videos
  99. result['page'] = pg
  100. result['pagecount'] = 9999
  101. result['limit'] = 2
  102. result['total'] = 999999
  103. return result
  104. def get_hot(self, pg):
  105. result = {}
  106. url = 'https://api.live.bilibili.com/room/v1/room/get_user_recommend?page=%s&page_size=10' % pg
  107. rsp = self.fetch(url, headers=self.header, cookies=self.cookies)
  108. content = rsp.text
  109. jo = json.loads(content)
  110. if jo['code'] == 0:
  111. videos = []
  112. vodList = jo['data']
  113. for vod in vodList:
  114. aid = str(vod['roomid']).strip()
  115. title = vod['title'].replace("<em class=\"keyword\">", "").replace("</em>", "").replace("&quot;", '"')
  116. img = vod['user_cover'].strip()
  117. remark = vod['watched_show']['text_small'].strip() + " " + vod['uname'].strip()
  118. videos.append({
  119. "vod_id": aid + '&live',
  120. "vod_name": title,
  121. "vod_pic": img + '@672w_378h_1c.jpg',
  122. "vod_remarks": remark
  123. })
  124. result['list'] = videos
  125. result['page'] = pg
  126. result['pagecount'] = 9999
  127. result['limit'] = 2
  128. result['total'] = 999999
  129. return result
  130. def get_live(self, pg, parent_area_id, area_id):
  131. result = {}
  132. url = 'https://api.live.bilibili.com/xlive/web-interface/v1/second/getList?platform=web&parent_area_id=%s&area_id=%s&sort_type=online&page=%s' % (
  133. parent_area_id, area_id, pg)
  134. rsp = self.fetch(url, headers=self.header, cookies=self.cookies)
  135. content = rsp.text
  136. jo = json.loads(content)
  137. if jo['code'] == 0:
  138. videos = []
  139. vodList = jo['data']['list']
  140. for vod in vodList:
  141. aid = str(vod['roomid']).strip()
  142. title = vod['title'].replace("<em class=\"keyword\">", "").replace("</em>", "").replace("&quot;", '"')
  143. img = vod.get('cover').strip()
  144. remark = vod['watched_show']['text_small'].strip() + " " + vod['uname'].strip()
  145. videos.append({
  146. "vod_id": aid + '&live',
  147. "vod_name": title,
  148. "vod_pic": img + '@672w_378h_1c.jpg',
  149. "vod_remarks": remark
  150. })
  151. result['list'] = videos
  152. result['page'] = pg
  153. result['pagecount'] = 9999
  154. result['limit'] = 2
  155. result['total'] = 999999
  156. return result
  157. def get_fav(self, pg):
  158. result = {}
  159. url = 'https://api.live.bilibili.com/xlive/web-ucenter/v1/xfetter/GetWebList?page=%s&page_size=10' % pg
  160. rsp = self.fetch(url, headers=self.header, cookies=self.cookies)
  161. content = rsp.text
  162. jo = json.loads(content)
  163. videos = []
  164. vodList = jo['data']['rooms']
  165. for vod in vodList:
  166. aid = str(vod['room_id']).strip()
  167. title = vod['title'].replace("<em class=\"keyword\">", "").replace("</em>", "").replace("&quot;", '"')
  168. img = vod['cover_from_user'].strip()
  169. remark = vod['uname'].strip()
  170. videos.append({
  171. "vod_id": aid + '&live',
  172. "vod_name": title,
  173. "vod_pic": img + '@672w_378h_1c.jpg',
  174. "vod_remarks": remark
  175. })
  176. result['list'] = videos
  177. result['page'] = pg
  178. result['pagecount'] = 9999
  179. result['limit'] = 2
  180. result['total'] = 999999
  181. return result
  182. def get_history(self):
  183. result = {}
  184. url = 'https://api.bilibili.com/x/web-interface/history/cursor?ps=21&type=live'
  185. rsp = self.fetch(url, headers=self.header, cookies=self.cookies)
  186. content = rsp.text
  187. jo = json.loads(content)
  188. if jo['code'] == 0:
  189. videos = []
  190. vodList = jo['data']['list']
  191. for vod in vodList:
  192. aid = str(vod['history']['oid']).strip()
  193. title = vod['title'].replace("<em class=\"keyword\">", "").replace("</em>", "").replace("&quot;", '"')
  194. img = vod['cover'].strip()
  195. remark = str(vod['live_status']).replace("0", "未开播").replace("1", "") +" " + vod['author_name'].strip()
  196. videos.append({
  197. "vod_id": aid + '&live',
  198. "vod_name": title,
  199. "vod_pic": img + '@672w_378h_1c.jpg',
  200. "vod_remarks": remark
  201. })
  202. result['list'] = videos
  203. result['page'] = 1
  204. result['pagecount'] = 1
  205. result['limit'] = 90
  206. result['total'] = 999999
  207. return result
  208. def categoryContent(self, tid, pg, filter, extend):
  209. result = {}
  210. if len(self.cookies) <= 0:
  211. self.getCookie()
  212. if tid.isdigit():
  213. parent_area_id = tid
  214. area_id = 0
  215. if 'area_id' in extend:
  216. area_id = extend['area_id']
  217. return self.get_live(pg=pg, parent_area_id=parent_area_id, area_id=area_id)
  218. if tid == "推荐":
  219. return self.get_recommend(pg)
  220. if tid == "热门":
  221. return self.get_hot(pg)
  222. if tid == "我的关注":
  223. return self.get_fav(pg)
  224. if tid == "观看记录":
  225. return self.get_history()
  226. return result
  227. def cleanSpace(self, str):
  228. return str.replace('\n', '').replace('\t', '').replace('\r', '').replace(' ', '')
  229. def detailContent(self, array):
  230. arrays = array[0].split("&")
  231. room_id = arrays[0]
  232. url = "https://api.live.bilibili.com/room/v1/Room/get_info?room_id=%s" % room_id
  233. rsp = self.fetch(url, headers=self.header, cookies=self.cookies)
  234. jRoot = json.loads(rsp.text)
  235. if jRoot.get('code') == 0:
  236. jo = jRoot['data']
  237. title = jo['title'].replace("<em class=\"keyword\">", "").replace("</em>", "")
  238. pic = jo.get("user_cover")
  239. desc = jo.get('description')
  240. uid = str(jo["uid"])
  241. info = {}
  242. self.bilibili.get_up_info(uid, info)
  243. dire = self.get_live_userInfo(uid)
  244. self.bilibili.up_mid = uid
  245. typeName = jo['parent_area_name'] + '--' + jo['area_name']
  246. if jo['live_status'] == 0:
  247. live_status = "未开播"
  248. else:
  249. live_status = "开播时间:" + jo['live_time']
  250. remark = '在线人数:' + str(jo['online']).strip()
  251. vod = {
  252. "vod_id": room_id,
  253. "vod_name": title,
  254. "vod_pic": pic,
  255. "type_name": typeName,
  256. "vod_year": "",
  257. "vod_area": "bilidanmu",
  258. "vod_remarks": remark,
  259. "vod_actor": "关注:" + self.zh(jo.get('attention')) + " 房间号:" + room_id + " UID:" + uid,
  260. "vod_director": dire + '  ' + info['following'] + "  " + live_status,
  261. "vod_content": desc,
  262. }
  263. playUrl = 'flv线路原画$platform=web&quality=4_' + room_id + '#flv线路高清$platform=web&quality=3_' + room_id + '#h5线路原画$platform=h5&quality=4_' + room_id + '#h5线路高清$platform=h5&quality=3_' + room_id
  264. vod['vod_play_from'] = 'B站$$$关注/取关'
  265. secondP = info['followActName'] + '$' + str(uid) + '_' + str(info['followAct']) + '_follow#'
  266. vod['vod_play_url'] = playUrl + '$$$' + secondP
  267. result = {
  268. 'list': [
  269. vod
  270. ]
  271. }
  272. return result
  273. def searchContent(self, key, quick):
  274. url = 'https://api.bilibili.com/x/web-interface/search/type?search_type=live&keyword={0}&page=1'.format(key)
  275. if len(self.cookies) <= 0:
  276. self.getCookie()
  277. rsp = self.fetch(url, cookies=self.cookies, headers=self.header)
  278. content = rsp.text
  279. jo = json.loads(content)
  280. if jo['code'] != 0:
  281. rspRetry = self.fetch(url, cookies=self.cookies, headers=self.header)
  282. content = rspRetry.text
  283. jo = json.loads(content)
  284. videos1 = []
  285. if jo['data']['pageinfo']['live_room']['numResults'] != 0:
  286. vodList = jo['data']['result']['live_room']
  287. for vod in vodList:
  288. aid = str(vod['roomid']).strip()
  289. title = "直播间:" + vod['title'].strip().replace("<em class=\"keyword\">", "").replace("</em>", "") + "⇦" + key
  290. img = 'https:' + vod['user_cover'].strip()
  291. remark = vod['watched_show']['text_small'].strip() + " " + vod['uname'].strip()
  292. videos1.append({
  293. "vod_id": aid,
  294. "vod_name": title,
  295. "vod_pic": img + '@672w_378h_1c.jpg',
  296. "vod_remarks": remark
  297. })
  298. videos2 = []
  299. if jo['data']['pageinfo']['live_user']['numResults'] != 0:
  300. vodList = jo['data']['result']['live_user']
  301. for vod in vodList:
  302. aid = str(vod['roomid']).strip()
  303. title = "直播间:" + vod['uname'].strip().replace("<em class=\"keyword\">", "").replace("</em>", "") + " ⇦" + key
  304. img = 'https:' + vod['uface'].strip()
  305. remark = str(vod['live_status']).replace("0", "未开播").replace("1", "") + " 关注:" + self.zh(vod['attentions'])
  306. videos2.append({
  307. "vod_id": aid,
  308. "vod_name": title,
  309. "vod_pic": img + '@672w_378h_1c.jpg',
  310. "vod_remarks": remark
  311. })
  312. videos = videos1 + videos2
  313. result = {
  314. 'list': videos
  315. }
  316. return result
  317. def playerContent(self, flag, id, vipFlags):
  318. result = {}
  319. ids = id.split("_")
  320. if 'follow' in ids:
  321. self.bilibili.do_follow(ids[0], ids[1])
  322. return result
  323. url = 'https://api.live.bilibili.com/room/v1/Room/playUrl?cid=%s&%s' % (ids[1], ids[0])
  324. # raise Exception(url)
  325. if len(self.cookies) <= 0:
  326. self.getCookie()
  327. rsp = self.fetch(url, headers=self.header, cookies=self.cookies)
  328. jRoot = json.loads(rsp.text)
  329. if jRoot['code'] == 0:
  330. jo = jRoot['data']
  331. ja = jo['durl']
  332. url = ''
  333. if len(ja) > 0:
  334. url = ja[0]['url']
  335. result["parse"] = 0
  336. # result['type'] ="m3u8"
  337. result["playUrl"] = ''
  338. result["url"] = url
  339. result["header"] = {
  340. "Referer": "https://live.bilibili.com",
  341. "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'
  342. }
  343. if "h5" in ids[0]:
  344. result["contentType"] = ''
  345. else:
  346. result["contentType"] = 'video/x-flv'
  347. return result
  348. config = {
  349. "player": {},
  350. "filter": {
  351. "1": [
  352. {
  353. "key": "area_id",
  354. "name": "全部分类",
  355. "value": [
  356. {
  357. "n": "舞见",
  358. "v": "207"
  359. },
  360. {
  361. "n": "视频唱见",
  362. "v": "21"
  363. },
  364. {
  365. "n": "萌宅领域",
  366. "v": "530"
  367. },
  368. {
  369. "n": "视频聊天",
  370. "v": "145"
  371. },
  372. {
  373. "n": "情感",
  374. "v": "706"
  375. },
  376. {
  377. "n": "户外",
  378. "v": "123"
  379. },
  380. {
  381. "n": "日常",
  382. "v": "399"
  383. },
  384. ]
  385. },
  386. ],
  387. "2": [
  388. {
  389. "key": "area_id",
  390. "name": "热门分类",
  391. "value": [
  392. {
  393. "n": "英雄联盟",
  394. "v": "86"
  395. },
  396. {
  397. "n": "DOTA2",
  398. "v": "92"
  399. },
  400. {
  401. "n": "CS:GO",
  402. "v": "89"
  403. },
  404. {
  405. "n": "APEX英雄",
  406. "v": "240"
  407. },
  408. {
  409. "n": "永劫无间",
  410. "v": "666"
  411. },
  412. {
  413. "n": "穿越火线",
  414. "v": "88"
  415. },
  416. {
  417. "n": "守望先锋",
  418. "v": "87"
  419. },
  420. ]
  421. },
  422. ],
  423. "3": [
  424. {
  425. "key": "area_id",
  426. "name": "热门分类",
  427. "value": [
  428. {
  429. "n": "王者荣耀",
  430. "v": "35"
  431. },
  432. {
  433. "n": "和平精英",
  434. "v": "256"
  435. },
  436. {
  437. "n": "LOL手游",
  438. "v": "395"
  439. },
  440. {
  441. "n": "原神",
  442. "v": "321"
  443. },
  444. {
  445. "n": "第五人格",
  446. "v": "163"
  447. },
  448. {
  449. "n": "明日方舟",
  450. "v": "255"
  451. },
  452. {
  453. "n": "哈利波特:魔法觉醒",
  454. "v": "474"
  455. },
  456. ]
  457. },
  458. ],
  459. "6": [
  460. {
  461. "key": "area_id",
  462. "name": "热门分类",
  463. "value": [
  464. {
  465. "n": "主机游戏",
  466. "v": "236"
  467. },
  468. {
  469. "n": "战神",
  470. "v": "579"
  471. },
  472. {
  473. "n": "我的世界",
  474. "v": "216"
  475. },
  476. {
  477. "n": "独立游戏",
  478. "v": "283"
  479. },
  480. {
  481. "n": "怀旧游戏",
  482. "v": "237"
  483. },
  484. {
  485. "n": "大多数",
  486. "v": "726"
  487. },
  488. {
  489. "n": "弹幕互动玩法",
  490. "v": "460"
  491. },
  492. ]
  493. },
  494. ],
  495. "5": [
  496. {
  497. "key": "area_id",
  498. "name": "全部分类",
  499. "value": [
  500. {
  501. "n": "唱见电台",
  502. "v": "190"
  503. },
  504. {
  505. "n": "聊天电台",
  506. "v": "192"
  507. },
  508. {
  509. "n": "配音",
  510. "v": "193"
  511. },
  512. ]
  513. },
  514. ],
  515. "9": [
  516. {
  517. "key": "area_id",
  518. "name": "全部分类",
  519. "value": [
  520. {
  521. "n": "虚拟主播",
  522. "v": "371"
  523. },
  524. {
  525. "n": "3D虚拟主播",
  526. "v": "697"
  527. },
  528. ]
  529. },
  530. ],
  531. "10": [
  532. {
  533. "key": "area_id",
  534. "name": "全部分类",
  535. "value": [
  536. {
  537. "n": "生活分享",
  538. "v": "646"
  539. },
  540. {
  541. "n": "运动",
  542. "v": "628"
  543. },
  544. {
  545. "n": "搞笑",
  546. "v": "624"
  547. },
  548. {
  549. "n": "手工绘画",
  550. "v": "627"
  551. },
  552. {
  553. "n": "萌宠",
  554. "v": "369"
  555. },
  556. {
  557. "n": "美食",
  558. "v": "367"
  559. },
  560. {
  561. "n": "时尚",
  562. "v": "378"
  563. },
  564. {
  565. "n": "影音馆",
  566. "v": "33"
  567. },
  568. ]
  569. },
  570. ],
  571. "11": [
  572. {
  573. "key": "area_id",
  574. "name": "全部分类",
  575. "value": [
  576. {
  577. "n": "社科法律心理",
  578. "v": "376"
  579. },
  580. {
  581. "n": "人文历史",
  582. "v": "702"
  583. },
  584. {
  585. "n": "校园学习",
  586. "v": "372"
  587. },
  588. {
  589. "n": "职场·技能",
  590. "v": "377"
  591. },
  592. {
  593. "n": "科技",
  594. "v": "375"
  595. },
  596. {
  597. "n": "科学科普",
  598. "v": "710"
  599. },
  600. ]
  601. },
  602. ],
  603. "13": [
  604. {
  605. "key": "area_id",
  606. "name": "全部分类",
  607. "value": [
  608. {
  609. "n": "游戏赛事",
  610. "v": "561"
  611. },
  612. {
  613. "n": "体育赛事",
  614. "v": "562"
  615. },
  616. {
  617. "n": "赛事综合",
  618. "v": "563"
  619. },
  620. ]
  621. },
  622. ],
  623. }
  624. }
  625. header = {
  626. "Referer": "https://www.bilibili.com",
  627. "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'
  628. }
  629. def localProxy(self, param):
  630. return [200, "video/MP2T", action, ""]