效果图:
最近学习QTreeWidget,总想着做些什么,正好学习过一点简单的爬虫,就做了一个简易的“酷我音乐下载器”,界面可能不太好看,以后继续优化。
ui_kuwo.py
# -*- coding: utf-8 -*- # Form implementation generated from reading ui file 'ui_kuwo.ui' # # Created by: PyQt5 UI code generator 5.13.0 # # WARNING! All changes made in this file will be lost! from PyQt5 import QtCore, QtGui, QtWidgets class Ui_MainWindow(object): def setupUi(self, MainWindow): MainWindow.setObjectName("MainWindow") MainWindow.resize(800, 624) font = QtGui.QFont() font.setPointSize(10) MainWindow.setFont(font) self.centralwidget = QtWidgets.QWidget(MainWindow) self.centralwidget.setObjectName("centralwidget") self.lineEdit = QtWidgets.QLineEdit(self.centralwidget) self.lineEdit.setGeometry(QtCore.QRect(60, 20, 681, 41)) font = QtGui.QFont() font.setPointSize(12) self.lineEdit.setFont(font) self.lineEdit.setStyleSheet("border:2px groove gray;border-radius:10px;padding:2px 4px") self.lineEdit.setInputMask("") self.lineEdit.setText("") self.lineEdit.setObjectName("lineEdit") self.treeWidget = QtWidgets.QTreeWidget(self.centralwidget) self.treeWidget.setGeometry(QtCore.QRect(60, 110, 681, 411)) self.treeWidget.setObjectName("treeWidget") self.treeWidget.headerItem().setTextAlignment(0, QtCore.Qt.AlignCenter) font = QtGui.QFont() font.setPointSize(10) font.setBold(True) font.setWeight(75) self.treeWidget.headerItem().setFont(0, font) self.treeWidget.headerItem().setTextAlignment(1, QtCore.Qt.AlignCenter) font = QtGui.QFont() font.setPointSize(10) font.setBold(True) font.setWeight(75) self.treeWidget.headerItem().setFont(1, font) self.treeWidget.headerItem().setTextAlignment(2, QtCore.Qt.AlignCenter) font = QtGui.QFont() font.setPointSize(10) font.setBold(True) font.setWeight(75) self.treeWidget.headerItem().setFont(2, font) self.treeWidget.headerItem().setTextAlignment(3, QtCore.Qt.AlignCenter) font = QtGui.QFont() font.setPointSize(10) font.setBold(True) font.setWeight(75) self.treeWidget.headerItem().setFont(3, font) self.treeWidget.headerItem().setTextAlignment(4, QtCore.Qt.AlignCenter) font = QtGui.QFont() font.setPointSize(10) font.setBold(True) font.setWeight(75) self.treeWidget.headerItem().setFont(4, font) self.treeWidget.header().setDefaultSectionSize(130) self.btnSel_ALL = QtWidgets.QPushButton(self.centralwidget) self.btnSel_ALL.setGeometry(QtCore.QRect(210, 80, 75, 23)) self.btnSel_ALL.setObjectName("btnSel_ALL") self.btnSel_None = QtWidgets.QPushButton(self.centralwidget) self.btnSel_None.setGeometry(QtCore.QRect(340, 80, 75, 23)) self.btnSel_None.setObjectName("btnSel_None") self.btnSel_Invs = QtWidgets.QPushButton(self.centralwidget) self.btnSel_Invs.setGeometry(QtCore.QRect(470, 80, 75, 23)) self.btnSel_Invs.setObjectName("btnSel_Invs") self.label = QtWidgets.QLabel(self.centralwidget) self.label.setGeometry(QtCore.QRect(60, 530, 681, 16)) self.label.setText("") self.label.setObjectName("label") MainWindow.setCentralWidget(self.centralwidget) self.menubar = QtWidgets.QMenuBar(MainWindow) self.menubar.setGeometry(QtCore.QRect(0, 0, 800, 21)) self.menubar.setObjectName("menubar") MainWindow.setMenuBar(self.menubar) self.toolBar = QtWidgets.QToolBar(MainWindow) self.toolBar.setToolButtonStyle(QtCore.Qt.ToolButtonTextUnderIcon) self.toolBar.setObjectName("toolBar") MainWindow.addToolBar(QtCore.Qt.TopToolBarArea, self.toolBar) self.actSong_Download = QtWidgets.QAction(MainWindow) icon = QtGui.QIcon() icon.addPixmap(QtGui.QPixmap("Image/icon/download.jpg"), QtGui.QIcon.Normal, QtGui.QIcon.Off) self.actSong_Download.setIcon(icon) self.actSong_Download.setObjectName("actSong_Download") self.actSong_Search = QtWidgets.QAction(MainWindow) icon1 = QtGui.QIcon() icon1.addPixmap(QtGui.QPixmap("Image/icon/search.jpg"), QtGui.QIcon.Normal, QtGui.QIcon.Off) self.actSong_Search.setIcon(icon1) self.actSong_Search.setObjectName("actSong_Search") self.toolBar.addAction(self.actSong_Download) self.retranslateUi(MainWindow) QtCore.QMetaObject.connectSlotsByName(MainWindow) def retranslateUi(self, MainWindow): _translate = QtCore.QCoreApplication.translate MainWindow.setWindowTitle(_translate("MainWindow", "酷我音乐下载器")) self.lineEdit.setPlaceholderText(_translate("MainWindow", "请输入歌手名/歌曲名")) self.treeWidget.headerItem().setText(0, _translate("MainWindow", "序号")) self.treeWidget.headerItem().setText(1, _translate("MainWindow", "歌曲")) self.treeWidget.headerItem().setText(2, _translate("MainWindow", "歌手")) self.treeWidget.headerItem().setText(3, _translate("MainWindow", "专辑")) self.treeWidget.headerItem().setText(4, _translate("MainWindow", "时长")) self.btnSel_ALL.setText(_translate("MainWindow", "全选")) self.btnSel_None.setText(_translate("MainWindow", "全不选")) self.btnSel_Invs.setText(_translate("MainWindow", "反选")) self.toolBar.setWindowTitle(_translate("MainWindow", "toolBar")) self.actSong_Download.setText(_translate("MainWindow", "下载歌曲")) self.actSong_Download.setToolTip(_translate("MainWindow", "下载歌曲")) self.actSong_Search.setText(_translate("MainWindow", "搜索")) self.actSong_Search.setToolTip(_translate("MainWindow", "搜索"))
myMainWindow_kuwo.py
#!/usr/bin/env python # _*_ coding: UTF-8 _*_ """================================================= @Project -> File : Operate-system -> myMainWindow_kuwo_download.py @IDE : PyCharm @Author : zihan @Date : 2020/4/21 10:26 @Desc : =================================================""" import sys from PyQt5.QtWidgets import QApplication, QMainWindow, QTreeWidgetItem, QLineEdit from enum import Enum from PyQt5.QtCore import Qt, QThread, pyqtSignal from ui_kuwo import Ui_MainWindow import requests import os def create_folder(path): if os.path.exists(path): pass else: os.mkdir(path) # 节点类型的枚举类型 class TreeItemType(Enum): itTopItem = 1001 # 顶层节点 itGroupItem = 1002 # 分组节点 itImageItem = 1003 # 图片文件节点 class TreeColNum(Enum): # 目录树的列号的枚举类型 col_order = 0 # 序号列 col_song_name = 1 # 歌曲名列 col_singer_name = 2 # 歌手列 col_singer_album = 3 # 专辑列 col_song_time = 4 # 时长列 col_song_rid = 5 # rid class SongDownload(QThread): label_str = pyqtSignal(str) def __init__(self, path, song_url, song_name): super(SongDownload, self).__init__() self.__path = path self.__url = song_url self.__songname = song_name def run(self): self.label_str.emit("正在请求响应...请耐心等待") # self.label_str.emit("正在下载{}".format(self.__songname)) # print("正在下载{}".format(self.__songname)) data = requests.get(self.__url).content with open(self.__path + "/" + self.__songname + ".mp3", "wb") as f: f.write(data) self.label_str.emit(self.__songname + " 成功下载到" + self.__path) print(self.__songname + " 成功下载到" + self.__path) class QmyMainWindow(QMainWindow): def __init__(self, parent=None): super().__init__(parent) self.ui = Ui_MainWindow() self.ui.setupUi(self) self.thread = None self.itemFlags = Qt.ItemIsSelectable | Qt.ItemIsUserCheckable | Qt.ItemIsEnabled | Qt.ItemIsAutoTristate self.ui.lineEdit.addAction(self.ui.actSong_Search, QLineEdit.TrailingPosition) self.ui.treeWidget.hideColumn(5) # 当点击搜索时 self.ui.actSong_Search.triggered.connect(self.do_act_song_search_triggered) # 全选 self.ui.btnSel_ALL.clicked.connect(self.do_btn_sel_all_clicked) # 全不选 self.ui.btnSel_None.clicked.connect(self.do_btn_sel_none_clicked) # 反选 self.ui.btnSel_Invs.clicked.connect(self.do_btn_sel_invs_clicked) # 当点击下载歌曲时 self.ui.actSong_Download.triggered.connect(self.do_act_song_download_triggered) # 全选 def do_btn_sel_all_clicked(self): for i in range(self.ui.treeWidget.topLevelItemCount()): aItem = self.ui.treeWidget.topLevelItem(i) aItem.setCheckState(TreeColNum.col_order.value, Qt.Checked) # 全不选 def do_btn_sel_none_clicked(self): for i in range(self.ui.treeWidget.topLevelItemCount()): aItem = self.ui.treeWidget.topLevelItem(i) aItem.setCheckState(TreeColNum.col_order.value, Qt.Unchecked) # 反选 def do_btn_sel_invs_clicked(self): for i in range(self.ui.treeWidget.topLevelItemCount()): aItem = self.ui.treeWidget.topLevelItem(i) if aItem.checkState(TreeColNum.col_order.value) != Qt.Checked: aItem.setCheckState(TreeColNum.col_order.value, Qt.Checked) else: aItem.setCheckState(TreeColNum.col_order.value, Qt.Unchecked) # 当点击搜索按钮时 def do_act_song_search_triggered(self): # 获取歌手名或者歌曲名 search_text = self.ui.lineEdit.text() self.ui.treeWidget.clear() self.get_kuwo_songs(search_text) # 搜索之后列出歌单 def show_songs_tree(self, order, song_name, singer_name, singer_album, song_time, song_rid): # 创建节点 item = QTreeWidgetItem(TreeItemType.itTopItem.value) item.setText(TreeColNum.col_order.value, str(order+1)) item.setText(TreeColNum.col_song_name.value, song_name) item.setText(TreeColNum.col_singer_name.value, singer_name) item.setText(TreeColNum.col_singer_album.value, singer_album) item.setText(TreeColNum.col_song_time.value, song_time) item.setText(TreeColNum.col_song_rid.value, str(song_rid)) item.setFlags(self.itemFlags) item.setCheckState(TreeColNum.col_order.value, Qt.Checked) item.setData(TreeColNum.col_order.value, Qt.UserRole, "") # 设置文字居中 item.setTextAlignment(TreeColNum.col_order.value, Qt.AlignCenter) item.setTextAlignment(TreeColNum.col_song_name.value, Qt.AlignCenter) item.setTextAlignment(TreeColNum.col_singer_name.value, Qt.AlignCenter) item.setTextAlignment(TreeColNum.col_singer_album.value, Qt.AlignCenter) item.setTextAlignment(TreeColNum.col_song_time.value, Qt.AlignCenter) item.setTextAlignment(TreeColNum.col_song_rid.value, Qt.AlignCenter) self.ui.treeWidget.addTopLevelItem(item) # 获取歌曲,默认5页 def get_kuwo_songs(self, key, page=5): # 右键检查-->network-->在Name找到searchMusicBykeyWord?点开,在右侧可以看到请求头和url信息 headers = { 'User-Agent': "agent信息", 'Referer': "refer信息", 'csrf': "csrf信息", 'Cookie': "cookie信息" } order = 0 for i in range(1, page + 1): url = "http://www.kuwo.cn/api/www/search/searchMusicBykeyWord?key={}&pn={}".format(key, i) html = requests.get(url, headers=headers).json() data = html["data"]["list"] for dic_songs_info in data: song_rid = dic_songs_info["rid"] song_name = dic_songs_info["name"] singer_name = dic_songs_info["artist"] song_time = dic_songs_info["songTimeMinutes"] singer_album = dic_songs_info["album"] path_singer = "./酷我音乐/" + self.ui.lineEdit.text() create_folder(path_singer) self.show_songs_tree(order, song_name, singer_name, singer_album, song_time, song_rid) order = order + 1 def start_thread(self, path_singer, song_url, song_name): # 创建线程 self.thread = SongDownload(path_singer, song_url, song_name) # 连接信号 self.thread.label_str[str].connect(self.do_label_change) # 开启线程 self.thread.start() # 当点击下载 def do_act_song_download_triggered(self): for i in range(self.ui.treeWidget.topLevelItemCount()): aItem = self.ui.treeWidget.topLevelItem(i) if aItem.checkState(TreeColNum.col_order.value) != Qt.Checked: pass else: song_name = aItem.text(1) song_rid = int(aItem.text(5)) song_url = self.get_one_song_url(song_rid) path_singer = "./酷我音乐/" + self.ui.lineEdit.text() self.start_thread(path_singer, song_url, song_name) # 获取一首歌的url def get_one_song_url(self, rid): # 点开一首免费歌曲,找到url格式url?format,点开找到头信息 url = "http://www.kuwo.cn/url?format=mp3&rid={}&response=url&type=convert_url3&br=128kmp3&from=web&t=1587429921873&reqId=617f0321-8369-11ea-80b3-bbd056ce88a1".format( rid) headers = { 'Cookie': "", 'Referer': "", 'User-Agent': "", 'csrf': "" } data = requests.get(url, headers=headers).json() # {'code': 200, 'msg': 'success', 'url': 'https://win-web-ra01-sycdn.kuwo.cn/e9cbd04a0602f9f82c40e0f1800fa696/5e9e44a1/resource/n3/128/43/28/1310690697.mp3'} song_url = data["url"] return song_url def do_label_change(self, str_label): self.ui.label.setText(str_label) if __name__ == "__main__": app = QApplication(sys.argv) # 创建app,用QApplication类 form = QmyMainWindow() form.show() sys.exit(app.exec_())
下面说一些值得注意的点。
一、搜索歌曲时请求头信息
初学者容易在这个地方就卡住,我用的google浏览器,现在就这个跟大家分享一下。
首先,打开酷我音乐网页,随便搜索一个歌手名,比如周杰伦。
可以看到他的歌单,此时鼠标右击打开Inspect-->NetWork
在左边找到searchMusicByKeyWord这种样式单击鼠标左键,可以在右边看到url以及请求头信息。
二、下载歌曲时,url格式的获取
这是第二个值得注意的地方,这时,需要找到一个可以免费播放的歌曲,然后在network左侧找到url?format这种样式的单击鼠标左键,在右侧找到url链接(我个人是这样找的,但是我觉得原理可能并不是这样,如果没有免费歌曲的话,那岂不是下载不了,如果有谁知道正确简单的查找方法,欢迎在评论区分享给大家,谢谢。)