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 感谢楼主,楼主辛苦了。看源码发现下载后的命名都是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)
非常感谢,亲测有用 虽然有很好的下载B站视频的工具了,但还是很厉害的,另外就是注意文件的命名,下载的命名都是B站视频{:1_907:},还有就是可以研究下多P下载 楼主为何打包这么小 Ldfd 发表于 2020-6-18 21:31
楼主为何打包这么小
其实我还觉得挺大的了{:301_971:} jshon 发表于 2020-6-18 21:26
虽然有很好的下载B站视频的工具了,但还是很厉害的,另外就是注意文件的命名,下载的命名都是B站视频{:1_90 ...
好的,谢谢你的建议 xccxvb 发表于 2020-6-18 21:53
其实我还觉得挺大的了
随随便便就10M唉 Ldfd 发表于 2020-6-18 23:05
随随便便就10M唉
哈哈毕竟多线程,其实如果宽带够高的话理论上可以30m/s,因为单线程最高是就可以达到3m/s的。 xccxvb 发表于 2020-6-18 23:21
哈哈毕竟多线程,其实如果宽带够高的话理论上可以30m/s,因为单线程最高是就可以达到3m/s的。
emm我说的其实是文件大小 Ldfd 发表于 2020-6-18 23:23
emm我说的其实是文件大小
你是打包的虚拟环境有很多包吗?我打包出来只有6.7m的,你可以去看我的成品。