xccxvb 发表于 2020-6-18 21:12

B站视频多线程最高可达10倍速下载!

本帖最后由 xccxvb 于 2020-6-18 21:12 编辑

B站视频多线程10倍速下载!哔哩哔哩bilibili。
先上成果图
!(https://s1.ax1x.com/2020/06/18/NnuHSJ.png)
!(https://s1.ax1x.com/2020/06/18/NnuXex.png)
线程数由你下载的文件大小决定的,小文件一个线程就够了,大文件最多会开启10个线程,也就是10倍速下载!
代码分两个文件,一个是主文件,一个是写多线程的
这是主文件
```
import requests
import re
import json
from multithreading import thread

headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.61 Safari/537.36',
}

url = input("请输入视频地址:")
with open('SESSDATA.txt', 'r') as f:
    SESSDATA = f.read()
if SESSDATA == '0':
    print('检测到您未设置SESSDATA,最高只能下载480p画质哦!')
#获取BV号
if '?' in url:
    url = url.split('?')
    print(url)
bvid = re.search(r'BV.*', url).group()
print('BV号:'+bvid)
#获取cid
cid_json = requests.get('https://api.bilibili.com/x/player/pagelist?bvid={}&jsonp=jsonp'.format(bvid)).text
cid = re.search(r'{"cid":(\d+)', cid_json).group()
print('CID:'+cid)

#获取视频的av号
rsp = requests.get(url, headers=headers)
aid = re.search(r'"aid":(.*?),"', rsp.text).group()
print('AV号:'+aid)

#抓取视频真实地址,清晰度
qn = 16 #先设置一个默认低清晰度
headers['Referer'] = url
api_url = 'https://api.bilibili.com/x/player/playurl?cid={}&avid={}&qn={}&otype=json&requestFrom=bilibili-helper'.format(cid, aid, qn)
qn_dict = {}#用来存放清晰度选择参数
rsp = requests.get(api_url, headers=headers).content
rsp = json.loads(rsp)
qn_accept_description = rsp.get('data').get('accept_description')
qn_accept_quality = rsp.get('data').get('accept_quality')
print('下载视频清晰度选择')
for i, j, xuhao in zip(qn_accept_description, qn_accept_quality, range(len(qn_accept_quality))):
    print(str(xuhao+1)+':'+i)
    qn_dict = j
xuhao = input('请选择(输入清晰度前的标号):')
qn = qn_dict
print('清晰度参数qn:'+str(qn))
api_url = 'https://api.bilibili.com/x/player/playurl?cid={}&avid={}&qn={}&otype=json&requestFrom=bilibili-helper'.format(cid, aid, qn)
#print('api_url='+api_url)
cookies = {}
cookies['SESSDATA'] = SESSDATA #这里输入你的SESSDATA
rsp = requests.get(api_url, headers=headers, cookies=cookies).content #这里代cookies才能得到会员或者登录后才能下载的视频的链接
rsp = json.loads(rsp)
real_url = rsp.get('data').get('durl').get('url')
print('成功获取视频直链!')
print('正在开启多线程极速下载……')
thread(real_url, url, 'b站视频.flv')#多线程下载

#把上面那行删掉,把下面注释去掉就是单线程下载
#content = requests.get(real_url, headers=headers).content
#with open('1.flv', 'wb') as f:
#    f.write(content)


```
这是多线程文件:
```
import requests
import threading
import datetime
import time
#改headers参数和url就好了
def thread(url, Referer, file_name):
# print(r.status_code, r.headers)
headers = {
      'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.61 Safari/537.36',
      'Referer': Referer
}
r = requests.get(url, headers=headers, stream=True, timeout=30)
all_thread = 1
# 获取视频大小
file_size = int(r.headers['content-length'])
# 如果获取到文件大小,创建一个和需要下载文件一样大小的文件
if file_size:
    fp = open(file_name, 'wb')
    fp.truncate(file_size)
    print('视频大小:' + str(int(file_size / 1024 / 1024)) + "MB")
    fp.close()
# 每个线程每次下载大小为5M
size = 5242880
# 当前文件大小需大于5M
if file_size > size:
    # 获取总线程数
    all_thread = int(file_size / size)
    # 设最大线程数为10,如总线程数大于10
    # 线程数为10
    if all_thread > 10:
      all_thread = 10
part = file_size // all_thread
threads = []
starttime = datetime.datetime.now().replace(microsecond=0)
for i in range(all_thread):
    # 获取每个线程开始时的文件位置
    start = part * i
    # 获取每个文件结束位置
    if i == all_thread - 1:
      end = file_size
    else:
      end = start + part
    if i > 0:
      start += 1
    headers = headers.copy()
    headers['Range'] = "bytes=%s-%s" % (start, end)
    t = threading.Thread(target=Handler, name='线程-' + str(i),
               kwargs={'start': start, 'end': end, 'url': url, 'filename': file_name, 'headers': headers})
    t.setDaemon(True)
    threads.append(t)
# 线程开始
for t in threads:
    time.sleep(0.2)
    t.start()
# 等待所有线程结束
print('正在下载……')
for t in threads:
    t.join()
endtime = datetime.datetime.now().replace(microsecond=0)
print('下载完成!用时:%s' % (endtime - starttime))
def Handler(start, end, url, filename, headers={}):
tt_name = threading.current_thread().getName()
print(tt_name + ' 已启动')
r = requests.get(url, headers=headers, stream=True)
total_size = end - start
downsize = 0
startTime = time.time()
with open(filename, 'r+b') as fp:
    fp.seek(start)
    var = fp.tell()
    for chunk in r.iter_content(204800):
      if chunk:
      fp.write(chunk)
      downsize += len(chunk)
      line = tt_name + '-downloading %d KB/s - %.2f MB, 共 %.2f MB'
      line = line % (
          downsize / 1024 / (time.time() - startTime), downsize / 1024 / 1024,
          total_size / 1024 / 1024)
      print(line, end='\r')
if __name__ == '__main__':
url = input('输入视频链接(请输入视频原链):')
thread(url)
```
这个代码太多了,我就用注释来解释,不单独说明了,如果有不会的就在帖子下面留言,我会的都会帮你解答的。
成品在这里:https://www.52pojie.cn/thread-1203083-1-1.html

microjun 发表于 2020-6-20 12:35

感谢楼主,楼主辛苦了。看源码发现下载后的命名都是B站视频,所以我做了一下改进,仅改了视频保存的名称,其他核心功能并没有动。新引入了BeautifulSoup库,对视频地址url进行了解析,抽取得到视频的名称name,并进行保存。

import re
import json
from multiprocessing import thread
import requests
from bs4 import BeautifulSoup

headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.61 Safari/537.36',
}

url = input("请输入视频地址:")
with open('SESSDATA.txt', 'r') as f:
    SESSDATA = f.read()
if SESSDATA == '0':
    print('检测到您未设置SESSDATA,最高只能下载480p画质哦!')

# 获取视频名称
r = requests.get(url)
r.encoding = 'utf-8'
soup = BeautifulSoup(r.text, 'html.parser')
name = soup.title.text.split('_')
print(name)

# 获取BV号
if '?' in url:
    url = url.split('?')
    print(url)
bvid = re.search(r'BV.*', url).group()
print('BV号:' + bvid + "1111")
# 获取cid
cid_json = requests.get('https://api.bilibili.com/x/player/pagelist?bvid={}&jsonp=jsonp'.format(bvid)).text
print(cid_json)
cid = re.search(r'{"cid":(\d+)', cid_json).group()
print('CID:' + cid)
# 获取视频的av号
rsp = requests.get(url, headers=headers)
aid = re.search(r'"aid":(.*?),"', rsp.text).group()
print('AV号:' + aid)


# 抓取视频真实地址,清晰度
qn = 16# 先设置一个默认低清晰度
headers['Referer'] = url
api_url = 'https://api.bilibili.com/x/player/playurl?cid={}&avid={}&qn={}&otype=json&requestFrom=bilibili-helper'.format(
    cid, aid, qn)
qn_dict = {}# 用来存放清晰度选择参数
rsp = requests.get(api_url, headers=headers).content
rsp = json.loads(rsp)
qn_accept_description = rsp.get('data').get('accept_description')
qn_accept_quality = rsp.get('data').get('accept_quality')
print('下载视频清晰度选择')
for i, j, xuhao in zip(qn_accept_description, qn_accept_quality, range(len(qn_accept_quality))):
    print(str(xuhao + 1) + ':' + i)
    qn_dict = j
xuhao = input('请选择(输入清晰度前的标号):')
qn = qn_dict
print('清晰度参数qn:' + str(qn))


api_url = 'https://api.bilibili.com/x/player/playurl?cid={}&avid={}&qn={}&otype=json&requestFrom=bilibili-helper'.format(
    cid, aid, qn)
# print('api_url='+api_url)
cookies = {}
cookies['SESSDATA'] = SESSDATA# 这里输入你的SESSDATA
rsp = requests.get(api_url, headers=headers, cookies=cookies).content# 这里代cookies才能得到会员或者登录后才能下载的视频的链接
rsp = json.loads(rsp)
real_url = rsp.get('data').get('durl').get('url')
print('成功获取视频直链!')
print('正在开启多线程极速下载……')
thread(real_url, url, name + '.flv')# 多线程下载

# 把上面那行删掉,把下面注释去掉就是单线程下载
# content = requests.get(real_url, headers=headers).content
# with open('1.flv', 'wb') as f:
#    f.write(content)

dajiaoban99 发表于 2020-6-18 23:13

非常感谢,亲测有用

jshon 发表于 2020-6-18 21:26

虽然有很好的下载B站视频的工具了,但还是很厉害的,另外就是注意文件的命名,下载的命名都是B站视频{:1_907:},还有就是可以研究下多P下载

Ldfd 发表于 2020-6-18 21:31

楼主为何打包这么小

xccxvb 发表于 2020-6-18 21:53

Ldfd 发表于 2020-6-18 21:31
楼主为何打包这么小

其实我还觉得挺大的了{:301_971:}

xccxvb 发表于 2020-6-18 21:55

jshon 发表于 2020-6-18 21:26
虽然有很好的下载B站视频的工具了,但还是很厉害的,另外就是注意文件的命名,下载的命名都是B站视频{:1_90 ...

好的,谢谢你的建议

Ldfd 发表于 2020-6-18 23:05

xccxvb 发表于 2020-6-18 21:53
其实我还觉得挺大的了

随随便便就10M唉

xccxvb 发表于 2020-6-18 23:21

Ldfd 发表于 2020-6-18 23:05
随随便便就10M唉

哈哈毕竟多线程,其实如果宽带够高的话理论上可以30m/s,因为单线程最高是就可以达到3m/s的。

Ldfd 发表于 2020-6-18 23:23

xccxvb 发表于 2020-6-18 23:21
哈哈毕竟多线程,其实如果宽带够高的话理论上可以30m/s,因为单线程最高是就可以达到3m/s的。

emm我说的其实是文件大小

xccxvb 发表于 2020-6-18 23:26

Ldfd 发表于 2020-6-18 23:23
emm我说的其实是文件大小

你是打包的虚拟环境有很多包吗?我打包出来只有6.7m的,你可以去看我的成品。
页: [1] 2 3 4
查看完整版本: B站视频多线程最高可达10倍速下载!