*此程序仅为学习python所写。
程序功能:通过链接下载b站(www.bilibili.com)视频保存到本地指定目录。
一、PyQt设计界面
二、编写代码
- 下载按钮
res = requests.get(self.txtLink.text()) #获取网页数据
self.downloadProgress(1)
bf = BeautifulSoup(res.text,features = "html.parser")
fileName = bf.find_all("span",class_ = "tit") #提取视频标题
fileName = fileName[0].text.replace('\xa0'*8,'\n\n') #去除文字标签
for i in "/\\*:?<>|\"":
fileName = fileName.replace(i,"") #去除标题中不能用作文件名的特殊字符
此部分代码用作获取目标视频的标题,作为保存至本地后的文件名。
这里关于Beautifulsoup4的用法参考:《基于Python3的网络爬虫脚本》
bvid = self.txtLink.text()
bvid = bvid[bvid.find("BV"):len(bvid)] #获取视频BV号
url = "https://api.bilibili.com/x/player/pagelist?bvid=%s&jsonp=jsonp" % bvid
cid = str(requests.get(url,headers=headers).json()["data"][0]["cid"])
downloadUrl = "https://api.bilibili.com/x/player/playurl?cid=%s&bvid=%s&qn=64&type=&otype=json" % (cid,bvid)
contents = requests.get(downloadUrl).json()
dataUrl = contents["data"]["durl"][0]["url"]
dataSize = contents["data"]["durl"][0]["size"]
flv_host = re.findall("https://(.*)com",dataUrl,re.I)
head["Host"] = flv_host[0] + "com"
head["Range"] = "bytes=0-%s" % dataSize
此部分代码用于获取视频下载链接。由于b站视频不能直接获取下载链接,这里参考 https://www.bilibili.com/read/cv9898845 的方法获取视频下载链接。
这里我使用find()方法和[ : ]运算符提取链接中视频BV号。
res = requests.get(dataUrl, headers=head, stream=True, verify=False)
chunk_size = 1024
count = 1
f = open(self.txtFileSaveAdd.text() + "/" + fileName + ".flv","wb") #下载视频
for i in res.iter_content(chunk_size):
f.write(i)
self.downloadProgress(int((count/(dataSize/chunk_size))*100)+1)
count += 1
f.close()
self.downloadProgress(100)
此部分代码用于下载视频,通过open()在指定的目录下创建以视频标题命名的文件,每次写入1024字节数据来逐步下载视频,并通过进度条实时更新下载进度。
整段下载程序可用try...except进行异常的处理,比如当下载链接或保存地址未填写时,下载状态显示对应提示。
- 清空按钮
def init(self):
self.txtFileSaveAdd.setText("")
self.txtLink.setText("")
self.progressBar.setValue(0)
self.labState.setText("准备下载。")
此段程序用于在点击清空按钮后,所有控件恢复到程序初始状态,方便下一次下载。
- 选择目录按钮
def getFileAdd(self):
self.txtFileSaveAdd.setText(QFileDialog.getExistingDirectory())
此段程序用于点击“…”按钮后,弹出选择目标文件夹的窗口,然后将目标路径存入地址文本框。
- 下载状态与进度条
def downloadProgress (self,progress):
if progress < 100:
self.labState.setText("Downloading...")
elif progress == 100:
self.labState.setText("下载完成!")
self.progressBar.setValue(progress)
此段程序用于同步下载状态与进度条。
三、完整代码
import re
import sys
import requests
from PyQt5 import QtCore, QtGui, QtWidgets
from bs4 import BeautifulSoup
from PyQt5.QtWidgets import QFileDialog
from Ui_MainWindow import Ui_MainWindow
requests.packages.urllib3.disable_warnings()
class CMainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
def __init__(self, parent = None):
super(CMainWindow, self).__init__(parent)
self.setupUi(self)
# 主窗体设置
self.show()
def download(self): #下载
headers = {'User-Agent':'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.89 Safari/537.36 SLBrowser/7.0.0.4071 SLBChan/21'}
head = {
"Host" : "",
"Range":"",
"Origin":"https://www.bilibili.com/",
"Referer":"https://www.bilibili.com/",
'User-Agent':'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.89 Safari/537.36 SLBrowser/7.0.0.4071 SLBChan/21'
}
try:
#### 获取视频标题 ####
res = requests.get(self.txtLink.text()) #获取网页数据
self.downloadProgress(1) #启动进度条 提示爬虫开始运行
bf = BeautifulSoup(res.text,features = "html.parser")
fileName = bf.find_all("span",class_ = "tit") #提取视频标题
fileName = fileName[0].text.replace('\xa0'*8,'\n\n') #去除标签
for i in "/\\*:?<>|\"":
fileName = fileName.replace(i,"") #去除标题中不能用作文件名的特殊字符
#### 获取下载链接 #### --参考https://www.bilibili.com/read/cv9898845
bvid = self.txtLink.text()
bvid = bvid[bvid.find("BV"):len(bvid)] #获取视频BV号
url = "https://api.bilibili.com/x/player/pagelist?bvid=%s&jsonp=jsonp" % bvid
cid = str(requests.get(url,headers=headers).json()["data"][0]["cid"])
downloadUrl = "https://api.bilibili.com/x/player/playurl?cid=%s&bvid=%s&qn=64&type=&otype=json" % (cid,bvid)
contents = requests.get(downloadUrl).json()
dataUrl = contents["data"]["durl"][0]["url"]
dataSize = contents["data"]["durl"][0]["size"]
flv_host = re.findall("https://(.*)com",dataUrl,re.I)
head["Host"] = flv_host[0] + "com"
head["Range"] = "bytes=0-%s" % dataSize
#### 下载视频 ####
res = requests.get(dataUrl, headers=head, stream=True, verify=False)
chunk_size = 1024
count = 1
f = open(self.txtFileSaveAdd.text() + "/" + fileName + ".flv","wb") #下载视频到指定目录
for i in res.iter_content(chunk_size):
f.write(i)
self.downloadProgress(int((count/(dataSize/chunk_size))*100)+1)
count += 1
f.close()
self.downloadProgress(100)
#异常处理
except requests.exceptions.MissingSchema:
self.labState.setText("无效的下载连接!")
self.progressBar.setValue(0)
except (FileNotFoundError,PermissionError):
self.labState.setText("无效的保存目录!")
self.progressBar.setValue(0)
except:
self.labState.setText("未知错误!")
self.progressBar.setValue(0)
def init(self): #清空文本框
self.txtFileSaveAdd.setText("")
self.txtLink.setText("")
self.progressBar.setValue(0)
self.labState.setText("准备下载。")
def getFileAdd(self): #获取保存路径
self.txtFileSaveAdd.setText(QFileDialog.getExistingDirectory())
def downloadProgress (self,progress): #同步下载状态与进度条
if progress < 100:
self.labState.setText("Downloading...")
elif progress == 100:
self.labState.setText("下载完成!")
self.progressBar.setValue(progress)
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
MainWindow = CMainWindow()
sys.exit(app.exec_())