Python-自制简易音乐播放器

news2024/12/23 11:14:33

文章目录

  • 前言
  • 一、代码
  • 二、代码实现
    • 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_labelMusicDownloader类的一个属性,用于存储对该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()

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1309012.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

JavaWeb笔记之MySQL数据库

#Author 流云 #Version 1.0 一、引言 1.1 现有的数据存储方式有哪些? Java程序存储数据(变量、对象、数组、集合),数据保存在内存中,属于瞬时状态存储。 文件(File)存储数据,保存…

飞致云与上海吉谛达成战略合作,获得Gitea企业版中国大陆地区独家代理权

2023年12月13日,中国领先的开源软件提供商FIT2CLOUD飞致云宣布与上海吉谛科技有限公司(以下简称为上海吉谛)正式达成战略合作,FIT2CLOUD飞致云获得上海吉谛旗下代码托管平台Gitea企业版中国大陆地区独家代理权。 Gitea项目&…

Github 2023-12-14开源项目日报 Top10

根据Github Trendings的统计,今日(2023-12-14统计)共有10个项目上榜。根据开发语言中项目的数量,汇总情况如下: 开发语言项目数量非开发语言项目5TypeScript项目2JavaScript项目1Jupyter Notebook项目1PHP项目1 基于项目的学习 创建周期&a…

[ 云计算 | Azure 实践 ] 在 Azure 门户中创建 VM 虚拟机并进行验证

文章目录 一、前言二、在 Azure Portal 中创建 VM三、验证已创建的虚拟机资源3.1 方法一:在虚拟机服务中查看验证3.1 方法二:在资源组服务中查看验证 四、文末总结 一、前言 本文会开始创建新系列的专栏,专门更新 Azure 云实践相关的文章。 …

CAN 三: STM32 CAN相关寄存器介绍

1、寄存器列表(F1/F4/F7) 寄存器名称作用CAN_MCRCAN主控制寄存器主要负责CAN工作模式的配置CAN_BTR位时序寄存器用来设置分频/TBS1/TBS2/TSWJ等参数,设置测试模式CAN_(T/R)IxR标识符寄存器存放(待发送/接收)的报文ID、扩展ID、IDE位及RTR位C…

MySQL 报错 You can‘t specify target table for update in FROM clause解决办法

You can’t specify target table for update in FROM clause 其含义是:不能在同一表中查询的数据作为同一表的更新数 单独执行复合查询是正常的,如下: 但是当执行子查询删除命令时,报如下错误 DELETE FROM abpusers WHERE Id I…

loki 如何格式化日志

部署 grafana-loki 首先介绍一下如何部署 官方文档:部署 grafana-loki 部署命令 设置集群的存储类,如果有默认可以不设置设置命名空间 helm install loki oci://registry-1.docker.io/bitnamicharts/grafana-loki --set global.storageClasslocal -n …

改进YOLOv8注意力系列二:结合CBAM、Coordinate Attention、deformable_LKA_Attention可变形大核注意力

改进YOLOv8注意力系列二:结合ACmix、Biformer、BAM注意力机制 代码CBAM注意力Coordinate Attention坐标注意力deformable_LKA_Attention可变形大核注意力加入方法各种yaml加入结构本文提供了改进 YOLOv8注意力系列包含不同的注意力机制以及多种加入方式,在本文中具有完整的代…

Linux查看端口使用情况

1、netstat命令 netstat命令用于显示与网络相关的信息,包括正在使用的端口。 netstat -tuln 其中,-t选项表示显示TCP连接,-u选项表示显示UDP连接,-l选项表示仅显示监听状态的连接,-n选项表示显示数字格式的IP地址和端口…

在Linux上安装配置Nginx高性能Web服务器

1 前言 Nginx是一个高性能的开源Web服务器,同时也可以作为反向代理服务器、负载均衡器、HTTP缓存以及作为一个邮件代理服务器。它以其出色的性能和灵活性而闻名,被广泛用于处理高流量的网站和应用程序。本文将介绍在Linux环境中安装Nginx的步骤&#xf…

设计模式之开篇

在软件开发的世界里,设计模式有如一本精妙的工程艺术指导准则,为我们提供了解决常见问题的优雅实现方案。然而,有些程序员可能会认为设计模式太过繁琐,一个简单的 if/else 语句就能解决问题,何必费心去学习这些看似复杂…

利用python批量压缩图教程:如何轻松减小图片大小

在日常的编程工作中,我们经常需要处理图像,例如上传、下载、显示、编辑等。有时候,我们需要对图像进行压缩,以减少占用的空间和带宽,提高加载速度和用户体验。那么,如何用Python来实现图像压缩呢&#xff1…

Linux_Ubuntu 系统入门

Ubuntu 系统是和 Windows 系统一样的大型桌面操作系统,因此功能非常强大。 本节的目的是掌握后续嵌入式开发所需的 Ubuntu 基本技能,比如系统的基本设置、常用的 shell 命令、vim 编译器的基本操作等等…… Ubuntu 的图形化界面操作和 Windows 下基本一致…

leetcode(平衡二叉树)

https://leetcode.cn/problems/balanced-binary-tree/description/ 这题的思路分成子问题就是计算左右子树的高度然后相减看看是不是大于1的就可以了,所以代码如下 int _isBalanced(struct TreeNode* root) {if(root NULL){return 0;}int leftdepth _isBalanced(…

dialog 在xml文件进行了自适应宽,但是失效了

如下图 讲述了为什么已经设置好了dialog的宽高 到了显示的时候就会失效的原因 解决方式 : 在自定的dialog中的onstart()方法中进行重新设置宽高 Window window getWindow();WindowManager.LayoutParams lp window.getAttributes();lp.height LinearLayout.La…

当当狸AR智能学习图集跨越千年文明传承,邀您“面对面”与虚拟诗人互动对诗

中华传统文化底蕴深厚,余韵悠长。即使经过千年的历史裂变,依然历久铭心慰藉着一代又一代人的灵魂。千百年后的今天,成为了我们独一无二的财富。 如今,国人学习中华传统文化的方式有很多,诗词集、动画影片、诗歌传颂等…

【51单片机系列】proteus中创建16x16LED点阵

本文参考来源: Proteus8.6中16x16LED点阵制作教程【Proteus】16乘16点阵滚动播放 文章目录 一、测试proteus中的8x8点阵驱动方式1.1 测试电流通过方向1.2 测试行列控制接口 二、使用proteus中的8x8点阵制作16x16LED点阵三、测试制作的16x16LED点阵四、使用自制的16x…

区块链的可拓展性研究【05】闪电网络

1.闪电网络:闪电网络是一种基于比特币区块链的 Layer2 扩容方案,它通过建立一个双向支付通道网络,实现了快速、低成本的小额支付。闪电网络的交易速度非常快,可以达到每秒数万笔交易,而且交易费用非常低,几…

关于“Python”的核心知识点整理大全18

目录 ​编辑 8.5 传递任意数量的实参 pizza.py 8.5.1 结合使用位置实参和任意数量实参 8.5.2 使用任意数量的关键字实参 user_profile.py 8.6 将函数存储在模块中 8.6.1 导入整个模块 pizza.py making_pizzas.py 8.6.2 导入特定的函数 8.6.3 使用 as 给函数指定别名…

git 相关操作说明

1.先下载git相关软件 下载地址: https://git-scm.com/download/win下载其中一个安装 2.打开gitee网站,注册账号 3.打开个人中心,选择ssh公钥,查看如何生成公钥 4.生成公钥后,添加相应的公钥 具体仓库操作 1.第一…