jlzzjlzz亚洲乱熟在线播放

系統城裝機大師 - 唯一官網:www.farandoo.com!

當前位置:首頁 > 腳本中心 > python > 詳細頁面

利用python 下載bilibili視頻

時間:2020-11-14來源:www.farandoo.com作者:電腦系統城

運行效果:

完整代碼

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
# !/usr/bin/python
# -*- coding:utf-8 -*-
# time: 2019/07/21--20:12
__author__ = 'Henry'
 
 
'''
項目: B站動漫番劇(bangumi)下載
版本2: 無加密API版,但是需要加入登錄后cookie中的SESSDATA字段,才可下載720p及以上視頻
API:
1.獲取cid的api為 https://api.bilibili.com/x/web-interface/view?aid=47476691 aid后面為av號
2.下載鏈接api為 https://api.bilibili.com/x/player/playurl?avid=44743619&cid=78328965&qn=32 cid為上面獲取到的 avid為輸入的av號 qn為視頻質量
注意:
但是此接口headers需要加上登錄后'Cookie': 'SESSDATA=3c5d20cf%2C1556704080%2C7dcd8c41' (30天的有效期)(因為現在只有登錄后才能看到720P以上視頻了)
不然下載之后都是最低清晰度,哪怕選擇了80也是只有480p的分辨率!!
'''
 
import requests, time, urllib.request, re
from moviepy.editor import *
import os, sys, threading, json
 
import imageio
 
# 訪問API地址
def get_play_list(aid, cid, quality):
  url_api = 'https://api.bilibili.com/x/player/playurl?cid={}&avid={}&qn={}'.format(cid, aid, quality)
  headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36',
    'Cookie': 'SESSDATA=13bd2abb%2C1619949439%2C2815d*b1', # 登錄B站后復制一下cookie中的SESSDATA字段,有效期1個月
    'Host': 'api.bilibili.com'
  }
  html = requests.get(url_api, headers=headers).json()
  # print(html)
  # 當下載會員視頻時,如果cookie中傳入的不是大會員的SESSDATA時就會返回: {'code': -404, 'message': '啥都木有', 'ttl': 1, 'data': None}
  if html['code'] != 0:
    print('注意!當前集數為B站大會員專享,若想下載,Cookie中請傳入大會員的SESSDATA')
    return 'NoVIP'
  video_list = []
  for i in html['data']['durl']:
    video_list.append(i['url'])
  print(video_list)
  return video_list
 
 
# 下載視頻
'''
 urllib.urlretrieve 的回調函數:
def callbackfunc(blocknum, blocksize, totalsize):
  @blocknum: 已經下載的數據塊
  @blocksize: 數據塊的大小
  @totalsize: 遠程文件的大小
'''
 
 
def Schedule_cmd(blocknum, blocksize, totalsize):
  speed = (blocknum * blocksize) / (time.time() - start_time)
  # speed_str = " Speed: %.2f" % speed
  speed_str = " Speed: %s" % format_size(speed)
  recv_size = blocknum * blocksize
 
  # 設置下載進度條
  f = sys.stdout
  pervent = recv_size / totalsize
  percent_str = "%.2f%%" % (pervent * 100)
  n = round(pervent * 50)
  s = ('#' * n).ljust(50, '-')
  f.write(percent_str.ljust(8, ' ') + '[' + s + ']' + speed_str)
  f.flush()
  # time.sleep(0.1)
  f.write('\r')
 
 
def Schedule(blocknum, blocksize, totalsize):
  speed = (blocknum * blocksize) / (time.time() - start_time)
  # speed_str = " Speed: %.2f" % speed
  speed_str = " Speed: %s" % format_size(speed)
  recv_size = blocknum * blocksize
 
  # 設置下載進度條
  f = sys.stdout
  pervent = recv_size / totalsize
  percent_str = "%.2f%%" % (pervent * 100)
  n = round(pervent * 50)
  s = ('#' * n).ljust(50, '-')
  print(percent_str.ljust(6, ' ') + '-' + speed_str)
  f.flush()
  time.sleep(2)
  # print('\r')
 
 
# 字節bytes轉化K\M\G
def format_size(bytes):
  try:
    bytes = float(bytes)
    kb = bytes / 1024
  except:
    print("傳入的字節格式不對")
    return "Error"
  if kb >= 1024:
    M = kb / 1024
    if M >= 1024:
      G = M / 1024
      return "%.3fG" % (G)
    else:
      return "%.3fM" % (M)
  else:
    return "%.3fK" % (kb)
 
 
# 下載視頻
def down_video(video_list, title, start_url, page):
  num = 1
  print('[正在下載第{}話視頻,請稍等...]:'.format(page) + title)
  currentVideoPath = os.path.join(sys.path[0], 'bilibili_video', title) # 當前目錄作為下載目錄
  for i in video_list:
    opener = urllib.request.build_opener()
    # 請求頭
    opener.addheaders = [
      # ('Host', 'upos-hz-mirrorks3.acgvideo.com'), #注意修改host,不用也行
      ('User-Agent', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.13; rv:56.0) Gecko/20100101 Firefox/56.0'),
      ('Accept', '*/*'),
      ('Accept-Language', 'en-US,en;q=0.5'),
      ('Accept-Encoding', 'gzip, deflate, br'),
      ('Range', 'bytes=0-'), # Range 的值要為 bytes=0- 才能下載完整視頻
      ('Referer', start_url), # 注意修改referer,必須要加的!
      ('Origin', 'https://www.bilibili.com'),
      ('Connection', 'keep-alive'),
 
    ]
    urllib.request.install_opener(opener)
    # 創建文件夾存放下載的視頻
    if not os.path.exists(currentVideoPath):
      os.makedirs(currentVideoPath)
    # 開始下載
    if len(video_list) > 1:
      urllib.request.urlretrieve(url=i, filename=os.path.join(currentVideoPath, r'{}-{}.flv'.format(title, num)),
                    reporthook=Schedule_cmd) # 寫成mp4也行 title + '-' + num + '.flv'
    else:
      urllib.request.urlretrieve(url=i, filename=os.path.join(currentVideoPath, r'{}.flv'.format(title)),
                    reporthook=Schedule_cmd) # 寫成mp4也行 title + '-' + num + '.flv'
    num += 1
 
 
# 合并視頻(20190802新版)
def combine_video(title_list):
  video_path = os.path.join(sys.path[0], 'bilibili_video') # 下載目錄
  for title in title_list:
    current_video_path = os.path.join(video_path ,title)
    if len(os.listdir(current_video_path)) >= 2:
      # 視頻大于一段才要合并
      print('[下載完成,正在合并視頻...]:' + title)
      # 定義一個數組
      L = []
      # 遍歷所有文件
      for file in sorted(os.listdir(current_video_path), key=lambda x: int(x[x.rindex("-") + 1:x.rindex(".")])):
        # 如果后綴名為 .mp4/.flv
        if os.path.splitext(file)[1] == '.flv':
          # 拼接成完整路徑
          filePath = os.path.join(current_video_path, file)
          # 載入視頻
          video = VideoFileClip(filePath)
          # 添加到數組
          L.append(video)
      # 拼接視頻
      final_clip = concatenate_videoclips(L)
      # 生成目標視頻文件
      final_clip.to_videofile(os.path.join(current_video_path, r'{}.mp4'.format(title)), fps=24, remove_temp=False)
      print('[視頻合并完成]' + title)
    else:
      # 視頻只有一段則直接打印下載完成
      print('[視頻合并完成]:' + title)
 
 
if __name__ == '__main__':
  start_time = time.time()
  # 用戶輸入番劇完整鏈接地址
  # 1. https://www.bilibili.com/bangumi/play/ep267692 (用帶ep鏈接)
  # 2. https://www.bilibili.com/bangumi/play/ss26878 (不要用這個ss鏈接,epinfo的aid會變成'-1')
  print('*' * 30 + 'B站番劇視頻下載小助手' + '*' * 30)
  print('[提示]: 1.如果您想下載720P60,1080p+,1080p60質量的視頻,請將35行代碼中的SESSDATA改成你登錄大會員后得到的SESSDATA,普通用戶的SESSDATA最多只能下載1080p的視頻')
  print('    2.若發現下載的視頻質量在720p以下,請將35行代碼中的SESSDATA改成你登錄后得到的SESSDATA(有效期一個月),而失效的SESSDATA就只能下載480p的視頻')
 
  start = input('請輸入您要下載的B站番劇的完整鏈接地址(例如:https://www.bilibili.com/bangumi/play/ep267692):')
  ep_url = start
  headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36'
  }
  html = requests.get(ep_url,headers=headers).text
  ep_info = re.search(r'INITIAL_STATE__=(.*?"]});', html).group(1)
  # print(ep_info)
  ep_info = json.loads(ep_info)
  print(ep_info)
  # print('您將要下載的番劇名為:' + ep_info['mediaInfo']['title']) # 字段格式太不統一了
  y = input('請輸入1或2 - 1.只下載當前一集 2.下載此番劇的全集:')
  # 1.如果只下載當前ep
  id_list = []
  if y == '1':
    try:
      id_list.append([ep_info['videoData']['aid'], ep_info['videoData']['cid'],
              ep_info['videoData']['title'] + ' ' + ep_info['videoData']['title']])
    except:
      id_list.append([ep_info['videoData']['aid'], ep_info['videoData']['cid'],
              '第' + str(ep_info['videoData']['index']) + '話 ' + ep_info['videoData']['index_title']])
  # 2.下載此番劇全部ep
  else:
    for i in ep_info['epList']:
      # if i['badge'] == '': # 當badge字段為'會員'時,接口返回404
      try:
        id_list.append([i['aid'], i['cid'],
                i['titleFormat'] + ' ' + i['title']])
      except:
        id_list.append([i['aid'], i['cid'],'第' + str(i['index']) + '話 ' + i['index_title']])
 
  # qn參數就是視頻清晰度
  # 可選值:
  # 116: 高清1080P60 (需要帶入大會員的cookie中的SESSDATA才行,普通用戶的SESSDATA最多只能下載1080p的視頻,不帶入SESSDATA就只能下載480p的)
  # 112: 高清1080P+ (hdflv2) (需要大會員)
  # 80: 高清1080P (flv)
  # 74: 高清720P60 (需要大會員)
  # 64: 高清720P (flv720)
  # 32: 清晰480P (flv480)
  # 16: 流暢360P (flv360)
  print('請輸入您要下載視頻的清晰度(1080p60:116;1080p+:112;1080p:80;720p60:74;720p:64;480p:32;360p:16; **注意:1080p+,1080p60,720p60都需要帶入大會員的cookie中的SESSDATA才行,普通用戶的SESSDATA最多只能下載1080p的視頻):')
  quality = input('請輸入116或112或80或74或64或32或16:')
  threadpool = []
  title_list = []
  page = 1
  print(id_list)
  for item in id_list:
    aid = str(item[0])
    cid = str(item[1])
    title = item[2]
    title = re.sub(r'[\/\\:*?"<>|]', '', title) # 替換為空的
    print('[下載番劇標題]:' + title)
    title_list.append(title)
    start_url = ep_url
    video_list = get_play_list(aid, cid, quality)
    start_time = time.time()
    # down_video(video_list, title, start_url, page)
    # 定義線程
    if video_list != 'NoVIP':
      th = threading.Thread(target=down_video, args=(video_list, title, start_url, page))
      # 將線程加入線程池
      threadpool.append(th)
    page += 1
 
  # 開始線程
  for th in threadpool:
    th.start()
  # 等待所有線程運行完畢
  for th in threadpool:
    th.join()
   
  # 最后合并視頻
  print(title_list)
  combine_video(title_list)
   
  end_time = time.time() # 結束時間
  print('下載總耗時%.2f秒,約%.2f分鐘' % (end_time - start_time, int(end_time - start_time) / 60))
  # 如果是windows系統,下載完成后打開下載目錄
  currentVideoPath = os.path.join(sys.path[0], 'bilibili_video') # 當前目錄作為下載目錄
  if (sys.platform.startswith('win')):
    os.startfile(currentVideoPath)

以上就是利用python 下載bilibili視頻的詳細內容

分享到:

相關信息

系統教程欄目

欄目熱門教程

人氣教程排行

站長推薦

熱門系統下載