文章目录
- 前言
- 一、代码
- 二、代码实现
- 1.库
- 2.做ui窗口
- 3爬虫
前言
原理简单:通过外链和歌曲Id拼接成下载链接来下载歌曲。
一、代码
做了个ui输入歌单链接:
注意这里歌单的url格式固定:
https://music.163.com/playlist?id=歌单id
import sys
from PyQt5.QtWidgets import QApplication, QWidget, QLabel, QVBoxLayout, QLineEdit, QPushButton, QFormLayout, \
QPlainTextEdit
from PyQt5.QtCore import Qt, QEventLoop
from PyQt5.QtGui import QIcon
import os
import time
import requests
from lxml import etree
class MusicDownloader(QWidget):
def __init__(self):
super().__init__()
self.setWindowTitle("Music Downloader")
self.setWindowIcon(QIcon("icon.png"))
self.setGeometry(600, 600, 700, 700)
self.url_label = QLabel("URL:")
self.url_input = QLineEdit()
self.download_btn = QPushButton("Download")
self.download_btn.clicked.connect(self.download_music)
self.output_window = QPlainTextEdit()
self.output_window.setReadOnly(True)
layout = QVBoxLayout()
layout.addWidget(self.url_label)
layout.addWidget(self.url_input)
layout.addWidget(self.download_btn)
layout.addWidget(self.output_window)
self.setLayout(layout)
current_file = os.path.realpath(__file__)
print("下载文件保存位置:", current_file+"\music")
self.output_window.appendPlainText(f"下载文件保存位置:{current_file}\music")
def download_music(self):
url = self.url_input.text()
if url.startswith("https://music.163.com/playlist?id="):
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36'
}
response = requests.get(url, headers=headers)
html = etree.HTML(response.text)
music_label_list = html.xpath('//a[contains(@href,"/song?")]')
if not os.path.exists('music'):
os.mkdir('music')
for music_label in music_label_list:
href = music_label.xpath('./@href')[0]
music_id = href.split('=')[1]
if music_id.isdigit():
music_name = music_label.xpath('./text()')[0]
music_url = 'http://music.163.com/song/media/outer/url?id=' + music_id
response = requests.get(music_url, headers=headers)
with open(f'./music/{music_name}.mp3', 'wb') as file:
file.write(response.content)
self.output_window.appendPlainText(f'《{music_name}》download success')
QApplication.processEvents(QEventLoop.ExcludeUserInputEvents)
time.sleep(1)
else:
self.output_window.appendPlainText("Invalid URL")
if __name__ == '__main__':
app = QApplication(sys.argv)
window = MusicDownloader()
window.show()
sys.exit(app.exec_())
二、代码实现
1.库
导入库:
import sys
from PyQt5.QtWidgets import QApplication, QWidget, QLabel, QVBoxLayout, QLineEdit, QPushButton, QFormLayout, \
QPlainTextEdit
from PyQt5.QtCore import Qt, QEventLoop
from PyQt5.QtGui import QIcon
2.做ui窗口
代码如下:
在Python中定义一个类,()中传的参数是这个类的父类
class MusicDownloader(QWidget):
init()方法是在类实例化时自动执行的特殊方法。当通过使用类名后面加上括号来创建类的实例时,init()方法会被自动调用。
self指实例化的对象
def __init__(self):
MusicDownloader类继承自QWidget类,而QWidget类是Qt库中的一个基本窗口部件类。调用super().init()实际上是在调用QWidget类的初始化函数,以确保MusicDownloader类的窗口部件正确初始化并获得父类的一些基本功能和属性。
super().__init__()
self.setWindowTitle("Music Downloader") //窗口标题
self.setWindowIcon(QIcon("icon.png")) //使用名为 "icon.png" 的图标文件作为图标(少用)
self.setGeometry(600, 600, 700, 700) //窗口的位置设置为(600, 600),宽度设置为700,高度设置为700
创建了一个QLabel
对象,并将其文本内容设置为"URL:"。QLabel
用于显示文本或图像,并且可以在用户界面中作为标签或标识显示某个元素。
在这个代码中,self.url_label
是MusicDownloader
类的一个属性,用于存储对该QLabel
对象的引用。通过这个引用,可以对这个标签进行进一步的设置和操作,比如更改文本内容、设置字体样式等。在用户界面的布局中,可以使用self.url_label
来添加、修改或移动这个标签。
self.url_label = QLabel("URL:")
创建了一个QLineEdit对象,即文本输入框。QLineEdit用于接收用户的文本输入,并可以在用户界面中用于输入和编辑文本。
在这个代码中,self.url_input是MusicDownloader类的一个属性,用于存储对该QLineEdit对象的引用。通过这个引用,可以对这个输入框进行进一步的设置和操作,比如获取用户输入的文本、设置默认文本、限制输入格式等。
在用户界面的布局中,可以使用self.url_input来添加、修改或移动这个输入框。可以通过连接到适当的槽函数,来处理这个输入框中的文本输入事件。
self.url_input = QLineEdit()
QLineEdit类提供了设置验证器的setValidator()方法。验证器可以用来指定输入的格式和规则。你可以使用内置的验证器类(如QIntValidator(输入整数)、QDoubleValidator(输入小数))或自定义的验证器类来限制输入。
edit = QLineEdit()
validator = QIntValidator()
edit.setValidator(validator)
QLineEdit还支持掩码功能。通过设置掩码,可以指定输入字段的格式,比如日期、时间、电话号码等。
以下是一个使用掩码限制输入为日期的示例:
edit = QLineEdit()
edit.setInputMask("9999-99-99")
制作一个按钮,按钮中文本内容:“Download”
这个按钮链接到函数download_music
self.download_btn = QPushButton("Download")
self.download_btn.clicked.connect(self.download_music)
QPlainTextEdit是一个多行文本编辑器部件,可以用于显示和编辑多行文本。
输出窗口权限为只读
self.output_window = QPlainTextEdit()
self.output_window.setReadOnly(True)
窗口组件布局:
//QHBoxLayout() 水平布局
//这行代码创建了一个垂直布局对象 QVBoxLayout,用于垂直地排列小部件。
layout = QVBoxLayout()
//排列部件
layout.addWidget(self.url_label)
layout.addWidget(self.url_input)
layout.addWidget(self.download_btn)
layout.addWidget(self.output_window)
//应用布局
self.setLayout(layout)
//在输出窗口添加文本
self.output_window.appendPlainText(f"下载文件保存位置:{current_file}\music")
class MusicDownloader(QWidget):
def __init__(self):
super().__init__()
self.setWindowTitle("Music Downloader")
//self.setWindowIcon(QIcon("icon.png"))
self.setGeometry(600, 600, 700, 700) //位置:(x,y)大小:(长,宽)
self.url_label = QLabel("URL:") //标签
self.url_input = QLineEdit() //输入框
self.download_btn = QPushButton("Download") //按钮
self.download_btn.clicked.connect(self.download_music) //按钮连接函数
self.output_window = QPlainTextEdit() //输出框
self.output_window.setReadOnly(True) //只读权限
layout = QVBoxLayout() //垂直布局
layout.addWidget(self.url_label) //布局
layout.addWidget(self.url_input) //布局
layout.addWidget(self.download_btn) //布局
layout.addWidget(self.output_window) //布局
self.setLayout(layout) //应用布局
current_file = os.path.realpath(__file__)
//在输出窗口添加文本
self.output_window.appendPlainText(f"下载文件保存位置:{current_file}\music")
3爬虫
def download_music(self):
url = self.url_input.text() //获取输入文本
//判断输入的是不是歌单网址
if url.startswith("https://music.163.com/playlist?id="):
headers = {
自行添加
}
response = requests.get(url, headers=headers)
html = etree.HTML(response.text)
//href属性值中包含/song的a标签,中有歌曲的id
music_label_list = html.xpath('//a[contains(@href,"/song?")]')
if not os.path.exists('music'):
os.mkdir('music')
for music_label in music_label_list:
href = music_label.xpath('./@href')[0]
music_id = href.split('=')[1]
if music_id.isdigit():
//歌曲名字就在a标签内部
music_name = music_label.xpath('./text()')[0]
//拼接url
music_url = 'http://music.163.com/song/media/outer/url?id=' + music_id
response = requests.get(music_url, headers=headers)
with open(f'./music/{music_name}.mp3', 'wb') as file:
file.write(response.content)
self.output_window.appendPlainText(f'《{music_name}》download success')
QApplication.processEvents(QEventLoop.ExcludeUserInputEvents) //循环内部事件时不鸟外部输入
time.sleep(1) //爬一个休息一秒
else:
//输入的不是歌单Url
self.output_window.appendPlainText("Invalid URL")
额外的小知识:
在用代码对窗口进行直接操作时:
time.sleep()会导致主线程被阻塞,使得窗口无法响应事件,包括关闭事件。因此,需要避免在主线程中使用time.sleep()来等待。
for i in range(10):
self.output_window.appendPlainText(i)
QApplication.processEvents(QEventLoop.ExcludeUserInputEvents)
time.sleep(3)
解决:
def download_music(self):
self.timer = QTimer()
self.timer.timeout.connect(self.update_output) //超时运行self.update_output
self.counter = 0
self.timer.start(3000) //设定3秒一次的触发超时运行self.update_output
def update_output(self):
self.output_window.appendPlainText(str(self.counter))
self.counter += 1
if self.counter >= 10:
self.timer.stop()