用pyQt5写个B站下载器
上回写个无损音乐下载器,由于没用线程池,所以一次下多了会卡,后来自己再改了下,用到线程池控制一次的线程数,好多了。代码就不再发上来了。这回B站的就试着用了下。论坛里别人也有下载器的软件,比我好多了,我是自己刚学的,代码传上来大伙帮着指点指点下了。from B站下载0710 import Ui_MainWindow
import sys
from lxml import html
etree=html.etree
import os
import re
import subprocess
from PyQt5 import QtCore
from PyQt5.QtCore importpyqtSignal,QCoreApplication,QThreadPool,QRunnable,QObject
import requests
import json
import random
import webbrowser
from PyQt5.QtWidgets import QDesktopWidget, QApplication, QFileDialog, QMessageBox, QTableWidgetItem,QProgressBar
from PyQt5 import QtWidgets
def random_user():
user1 = "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36"
user2 = "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-us) AppleWebKit/534.50 (KHTML, like Gecko) Version/5.1 Safari/534.50"
user3 = "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0;"
user4 = "Mozilla/5.0 (Windows NT 6.1; rv,2.0.1) Gecko/20100101 Firefox/4.0.1"
user5 = "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; TencentTraveler 4.0)"
user6 = "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; Trident/4.0; SE 2.X MetaSr 1.0; SE 2.X MetaSr 1.0; .NET CLR 2.0.50727; SE 2.X MetaSr 1.0)"
user7 = "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1)"
user8 = "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; Avant Browser)"
user =
user = random.choice(user)
return user
class Tasks(QObject):
updata_data = pyqtSignal(list)
updata_data2 = pyqtSignal(str,int)
class BackendThread(QRunnable):
def __init__(self,url,video_name,count):
super().__init__()
self.signal = Tasks()
self.url = url
self.video_name=video_name
self.count = count
def down_file(self,url,filename,file_row,count): #这个函数不知用协程会不会更快些
header = {"User-Agent": random_user(), "referer": "https://message.bilibili.com/"}
file_data = requests.get(url, headers=header, stream=True)
filesize = int(file_data.headers['Content-Length'])
offset = 0
fileobj = open(filename, 'wb')
if file_data.status_code == 200:
for chunk in file_data.iter_content(chunk_size=204800):
if not chunk:
break
fileobj.seek(offset)
fileobj.write(chunk)
offset += len(chunk)
proess = (offset / filesize) * 100
self.signal.updata_data.emit()
fileobj.close()
def run(self):
self.signal.updata_data.emit()
self.signal.updata_data.emit()
header={"User-Agent": random_user(),"referer":"https://message.bilibili.com/"}
resonpe=requests.get(self.url,headers=header)
json_data = re.findall(r'<script>window.__playinfo__=(.*?)</script>', resonpe.text)
json_data = json.loads(json_data)
audio_url = json_data["data"]["dash"]["audio"]["backupUrl"]
video_url = json_data["data"]["dash"]["video"]["backupUrl"]
video_bakname=self.video_name+'bak.mp4'
audio_bakname = self.video_name + 'bak.mp3'
video_fulname=self.video_name+'.mp4'
self.down_file(video_url,video_bakname,1,self.count)
self.down_file(audio_url, audio_bakname, 2, self.count)
self.signal.updata_data2.emit('开始合并',self.count)
word=r'ffmpeg -i '+video_bakname+' -i '+audio_bakname+' -c:v copy -c:a aac -strict experimental'+video_fulname
subprocess.call(word,shell=True)
self.signal.updata_data2.emit('合并成功', self.count)
os.remove(video_bakname)
os.remove(audio_bakname)
class firstfrom(QtWidgets.QMainWindow):
def __init__(self):
QtWidgets.QMainWindow.__init__(self)
self.ui = Ui_MainWindow()
self.ui.setupUi(self)
self.ui.pushButton.clicked.connect(self.page_find)
self.ui.pushButton_5.clicked.connect(self.change_dir)
self.ui.pushButton_4.clicked.connect(QCoreApplication.instance().quit)
self.ui.pushButton_2.clicked.connect(self.start_find)
self.ui.pushButton_3.clicked.connect(self.start_down)
self.pool = QThreadPool()
self.pool.globalInstance()
self.pool.setMaxThreadCount(int(self.ui.comboBox.currentText()))
self.ui.checkBox.clicked.connect(self.check)
self.ui.pushButton_6.clicked.connect(self.opendir)
def opendir(self):
if not os.path.exists(self.ui.label_5.text()):
os.mkdir(self.ui.label_5.text())
if self.ui.label_5.text()=='./B站下载/':
os.startfile(os.getcwd()+'/B站下载/')
else:
os.startfile(str(self.ui.label_5.text()))
def check(self):
if self.ui.tableWidget.rowCount() != 0:
for i in range(0, self.ui.tableWidget.rowCount()):
self.ui.tableWidget.item(i, 0).setCheckState(self.ui.checkBox.checkState())
def start_down(self):#开始下载的函数,用了线程池。可以控制同时下载几个
self.pool.setMaxThreadCount(int(self.ui.comboBox.currentText()))
if self.ui.tableWidget.rowCount() == 0:
msg_box = QMessageBox(QMessageBox.Warning, '警告', '请先搜索歌曲!')
msg_box.exec_()
else:
if not os.path.exists(self.ui.label_5.text()):
os.mkdir(self.ui.label_5.text())
row = self.ui.tableWidget.rowCount()
for num in range(0, row):
if self.ui.tableWidget.item(num, 0).checkState() == 2:
down_url=self.ui.lineEdit_2.text().split('?')+'?p='+str(num+1)
print(down_url)
viedio_name=self.ui.label_5.text()+'/'+self.ui.tableWidget.item(num,0).text()
self.backend = BackendThread(down_url,viedio_name,num)
self.backend.signal.updata_data.connect(self.text_write)
self.backend.signal.updata_data2.connect(self.text_write2)
self.pool.start(self.backend)
QApplication.processEvents()
def text_write2(self,word,cont): #用一个字符串跟行数来表示音视频的合并状态
new_item1 = QTableWidgetItem(word)
new_item1.setTextAlignment(QtCore.Qt.AlignCenter)
self.ui.tableWidget.setItem(cont, 3, QTableWidgetItem(new_item1))
def text_write(self,word): #用一个列表来接收信息显示进度条状态,1值进度条值,2进度条的列数,3进度条的行
if word==0:
banber=QProgressBar(self)
self.ui.tableWidget.setCellWidget(word,word,banber)
else:
self.ui.tableWidget.cellWidget(word,word).setValue(word)
def start_find(self): #根据链接搜索
if self.ui.lineEdit_2.text()=='':
msg_box = QMessageBox(QMessageBox.Warning, '警告', '请先输入要解析的地址')
msg_box.exec_()
else:
self.ui.tableWidget.clear()
self.ui.tableWidget.setColumnCount(4)
self.ui.tableWidget.setColumnWidth(0, 250)
self.ui.tableWidget.setColumnWidth(1, 250)
self.ui.tableWidget.setColumnWidth(2, 250)
self.ui.tableWidget.setColumnWidth(3, 250)
self.ui.tableWidget.setHorizontalHeaderLabels(['视频名', '视频下载状态', '音频下载状态', '音视合并状态'])
page_url=self.ui.lineEdit_2.text().split('?')
header = {"User-Agent": random_user(),"referer":"https://message.bilibili.com/"}
try:
reponse = requests.get(page_url, headers=header)
if reponse.status_code==200:
json_data = re.findall(r'"no_cache":false,"pages":(.*?),"subtitle"', reponse.text)
json_data = json.loads(json_data)
self.ui.tableWidget.setRowCount(len(json_data))
for i in range(len(json_data)):
# page = json_data["page"]
title1 = json_data["part"]
pattern = re.compile(r"[\/\\\:\*\?\"\<\>\|\&\ \/]")
title = re.sub(pattern, "", title1)
new_item1 = QTableWidgetItem(title)
new_item1.setTextAlignment(QtCore.Qt.AlignCenter)
self.ui.tableWidget.setItem(i, 0, QTableWidgetItem(new_item1))
self.ui.tableWidget.item(i, 0).setCheckState(0)
QApplication.processEvents()
except:
msg_box = QMessageBox(QMessageBox.Warning, '警告', '请输入正确的网址!')
msg_box.exec_()
def page_find(self): #调用浏览器打开B站的关键词搜索结果网页
if self.ui.lineEdit.text()!='':
url ='https://search.bilibili.com/all?keyword='+self.ui.lineEdit.text()
else:
url='https://www.bilibili.com/'
webbrowser.open(url, new=0, autoraise=True)
def change_dir(self):
dir_ = QFileDialog.getExistingDirectory(self, '选择文件夹', '/')
if dir_ != '':
self.ui.label_5.setText(dir_)
else:
self.ui.label_5.setText('./B站下载/')
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
w = firstfrom()
screen = QDesktopWidget().screenGeometry()
size = w.geometry()
w.setWindowTitle('B站下载器')
left = (screen.width() - size.width()) / 2
hight = (screen.height() - size.height()) / 2
w.move(left, hight)
w.show()
sys.exit(app.exec_())
下面这个是界面的代码
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'B站下载0710.ui'
#
# Created by: PyQt5 UI code generator 5.15.4
#
# WARNING: Any manual changes made to this file will be lost when pyuic5 is
# run again.Do not edit this file unless you know what you are doing.
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(1014, 671)
MainWindow.setFixedSize(MainWindow.width(), MainWindow.height())
MainWindow.setWindowFlags(QtCore.Qt.WindowMinimizeButtonHint)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.comboBox = QtWidgets.QComboBox(self.centralwidget)
self.comboBox.setGeometry(QtCore.QRect(690, 10, 91, 22))
self.comboBox.setObjectName("comboBox")
self.comboBox.addItem("")
self.comboBox.addItem("")
self.comboBox.addItem("")
self.comboBox.addItem("")
self.comboBox.addItem("")
self.comboBox.addItem("")
self.label_4 = QtWidgets.QLabel(self.centralwidget)
self.label_4.setGeometry(QtCore.QRect(530, 10, 161, 20))
font = QtGui.QFont()
font.setFamily("楷体")
font.setPointSize(14)
self.label_4.setFont(font)
self.label_4.setObjectName("label_4")
self.checkBox = QtWidgets.QCheckBox(self.centralwidget)
self.checkBox.setGeometry(QtCore.QRect(840, 0, 171, 41))
font = QtGui.QFont()
font.setFamily("楷体")
font.setPointSize(14)
self.checkBox.setFont(font)
self.checkBox.setObjectName("checkBox")
self.layoutWidget = QtWidgets.QWidget(self.centralwidget)
self.layoutWidget.setGeometry(QtCore.QRect(10, 0, 491, 71))
self.layoutWidget.setObjectName("layoutWidget")
self.horizontalLayout = QtWidgets.QHBoxLayout(self.layoutWidget)
self.horizontalLayout.setContentsMargins(0, 0, 0, 0)
self.horizontalLayout.setObjectName("horizontalLayout")
self.label = QtWidgets.QLabel(self.layoutWidget)
font = QtGui.QFont()
font.setFamily("楷体")
font.setPointSize(14)
self.label.setFont(font)
self.label.setObjectName("label")
self.horizontalLayout.addWidget(self.label)
self.lineEdit = QtWidgets.QLineEdit(self.layoutWidget)
self.lineEdit.setObjectName("lineEdit")
self.horizontalLayout.addWidget(self.lineEdit)
self.pushButton = QtWidgets.QPushButton(self.layoutWidget)
font = QtGui.QFont()
font.setFamily("楷体")
font.setPointSize(14)
self.pushButton.setFont(font)
self.pushButton.setObjectName("pushButton")
self.horizontalLayout.addWidget(self.pushButton)
self.layoutWidget1 = QtWidgets.QWidget(self.centralwidget)
self.layoutWidget1.setGeometry(QtCore.QRect(10, 70, 491, 61))
self.layoutWidget1.setObjectName("layoutWidget1")
self.horizontalLayout_2 = QtWidgets.QHBoxLayout(self.layoutWidget1)
self.horizontalLayout_2.setContentsMargins(0, 0, 0, 0)
self.horizontalLayout_2.setObjectName("horizontalLayout_2")
self.label_2 = QtWidgets.QLabel(self.layoutWidget1)
font = QtGui.QFont()
font.setFamily("楷体")
font.setPointSize(14)
self.label_2.setFont(font)
self.label_2.setObjectName("label_2")
self.horizontalLayout_2.addWidget(self.label_2)
self.lineEdit_2 = QtWidgets.QLineEdit(self.layoutWidget1)
self.lineEdit_2.setObjectName("lineEdit_2")
self.horizontalLayout_2.addWidget(self.lineEdit_2)
self.pushButton_2 = QtWidgets.QPushButton(self.layoutWidget1)
font = QtGui.QFont()
font.setFamily("楷体")
font.setPointSize(14)
self.pushButton_2.setFont(font)
self.pushButton_2.setObjectName("pushButton_2")
self.horizontalLayout_2.addWidget(self.pushButton_2)
self.pushButton_5 = QtWidgets.QPushButton(self.centralwidget)
self.pushButton_5.setGeometry(QtCore.QRect(530, 50, 171, 31))
font = QtGui.QFont()
font.setFamily("楷体")
font.setPointSize(14)
self.pushButton_5.setFont(font)
self.pushButton_5.setObjectName("pushButton_5")
self.label_5 = QtWidgets.QLabel(self.centralwidget)
self.label_5.setGeometry(QtCore.QRect(750, 50, 231, 31))
font = QtGui.QFont()
font.setFamily("楷体")
font.setPointSize(14)
self.label_5.setFont(font)
self.label_5.setObjectName("label_5")
self.tableWidget = QtWidgets.QTableWidget(self.centralwidget)
self.tableWidget.setGeometry(QtCore.QRect(10, 140, 1000, 520))
self.tableWidget.setMaximumSize(QtCore.QSize(1000, 520))
self.tableWidget.setObjectName("tableWidget")
self.tableWidget.setColumnCount(0)
self.tableWidget.setRowCount(0)
self.widget = QtWidgets.QWidget(self.centralwidget)
self.widget.setGeometry(QtCore.QRect(530, 80, 461, 51))
self.widget.setObjectName("widget")
self.horizontalLayout_3 = QtWidgets.QHBoxLayout(self.widget)
self.horizontalLayout_3.setContentsMargins(0, 0, 0, 0)
self.horizontalLayout_3.setObjectName("horizontalLayout_3")
self.pushButton_3 = QtWidgets.QPushButton(self.widget)
font = QtGui.QFont()
font.setFamily("楷体")
font.setPointSize(14)
self.pushButton_3.setFont(font)
self.pushButton_3.setObjectName("pushButton_3")
self.horizontalLayout_3.addWidget(self.pushButton_3)
self.pushButton_6 = QtWidgets.QPushButton(self.widget)
font = QtGui.QFont()
font.setFamily("楷体")
font.setPointSize(14)
self.pushButton_6.setFont(font)
self.pushButton_6.setObjectName("pushButton_6")
self.horizontalLayout_3.addWidget(self.pushButton_6)
self.pushButton_4 = QtWidgets.QPushButton(self.widget)
font = QtGui.QFont()
font.setFamily("楷体")
font.setPointSize(14)
self.pushButton_4.setFont(font)
self.pushButton_4.setObjectName("pushButton_4")
self.horizontalLayout_3.addWidget(self.pushButton_4)
MainWindow.setCentralWidget(self.centralwidget)
self.statusbar = QtWidgets.QStatusBar(MainWindow)
self.statusbar.setObjectName("statusbar")
MainWindow.setStatusBar(self.statusbar)
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
self.comboBox.setItemText(0, _translate("MainWindow", "5"))
self.comboBox.setItemText(1, _translate("MainWindow", "6"))
self.comboBox.setItemText(2, _translate("MainWindow", "7"))
self.comboBox.setItemText(3, _translate("MainWindow", "8"))
self.comboBox.setItemText(4, _translate("MainWindow", "9"))
self.comboBox.setItemText(5, _translate("MainWindow", "10"))
self.label_4.setText(_translate("MainWindow", "选择下载线程数"))
self.checkBox.setText(_translate("MainWindow", "全选/全不选"))
self.label.setText(_translate("MainWindow", "请输入要搜索的关键词"))
self.pushButton.setText(_translate("MainWindow", "打开网站"))
self.label_2.setText(_translate("MainWindow", "请复制要解析的地址"))
self.pushButton_2.setText(_translate("MainWindow", "开始解析"))
self.pushButton_5.setText(_translate("MainWindow", "请选择保存地址"))
self.label_5.setText(_translate("MainWindow", "./B站下载/"))
self.pushButton_3.setText(_translate("MainWindow", "开始下载"))
self.pushButton_6.setText(_translate("MainWindow", "打开下载目录"))
self.pushButton_4.setText(_translate("MainWindow", "退出程序"))
打包好程序链接在下面,ffmpeg跟主程序要放同一目录,音视频合并时要用到这个程序
链接:https://wws.lanzoui.com/iFXHyrlmq3e密码:3544 random_user()很优秀,可以考虑下fake_useragent
asynico会不会比pool好呢?
楼上的伙伴的you-get确实神器,,;www;www kk159 发表于 2021-7-19 12:33
random_user()很优秀,可以考虑下fake_useragent
asynico会不会比pool好呢?
楼上的伙伴的you-get确实神 ...
谢谢了,没想到还有这个随机生成的库,以后看来就用这个了,you-get下载的这个库,我还不知道下载进度什么在界面上实时更新显示出来啊。我也是刚学的,第三方库知道的不多 学习收藏 感谢分享 截几个运行的图吧。。 lz可以只做界面,下载的工作交给you-get 这个,我也在学python ,就是感觉,视频讲的都好简单,实战都好难 很少见到PY写UI 飘零星夜 发表于 2021-7-19 14:05
这个,我也在学python ,就是感觉,视频讲的都好简单,实战都好难
多实践啊,比如爬虫先找个简单的美女壁纸网来下,可以养颜,还能学东西,论坛里别人发的也多,可以参考学习啊。:lol
页:
[1]
2