您现在的位置是:首页 >技术杂谈 >5. 超炫酷的爬虫源代码-vip音乐下载器网站首页技术杂谈

5. 超炫酷的爬虫源代码-vip音乐下载器

安迪python学习笔记 2024-09-22 00:01:04
简介5. 超炫酷的爬虫源代码-vip音乐下载器

1. 准备工作

  1. 在电脑D盘新建一个【安迪笔记】文件夹。

  2. 【安迪笔记】文件夹里新建【2.爬虫笔记】文件夹。

  3. 【2.爬虫笔记】文件夹里新建【5.vip音乐爬虫】文件夹。

  4. 【5.vip音乐爬虫】文件夹里新建【5.vip音乐下载器.py】文件。

  5. 我用vscode编辑器打开【安迪笔记】文件夹。

vscode打开的文件夹决定了相对路径,这一步要重点关注。

【备注】

  1. 我写笔记需要用到【安迪笔记】里的其他资料,为了笔记方便,我才建了这么多文件夹 。

  2. 因为有太多太多的同学找不到最终输出的文件,所以我对建文件夹和py文件做了详细说明。

  3. 如果你能掌握绝对路径的知识,能找到输出的文件,直接建py文件写即可。

2. 安装第3方库

【程序需要导入的所有库】

import os
import tkinter as tk
import webbrowser
import requests
import tkinter.messagebox as mes_box
import PySimpleGUI as sg
from tkinter import ttk
from retrying import retry

2.1 os 库

os是Python的内置库,不需要额外安装。

os库提供了一系列与操作系统交互的函数。

包括文件操作、进程管理、环境变量等。

通过os库,可以实现对文件、目录、进程等的操作,方便程序的编写和管理。

2.2 tkinter库

tkinter:图形界面。

tkinter是Python的内置库,不需要额外安装。

它是一个图形用户界面(GUI)工具包。

可以用于创建窗口、按钮、标签、文本框等各种界面元素,以及实现用户与程序的交互。

它是Python中最常用的GUI库之一,适用于开发桌面应用程序。

2.3 webbrowser 库

webbrowser:网页浏览器。

webbrowser 是Python的内置库,不需要额外安装。

webbrowser 库的作用是打开一个浏览器窗口,并在其中显示指定的URL地址。

它提供了一种简单的方法来在Python程序中打开网页、查看文档、播放视频等。

例如,可以使用 webbrowser.open() 函数来打开一个指定的URL地址,如下所示:

【代码示例】

# 1. 导入webbrowser库
import webbrowser

# 2. 定义一个url变量
url = 'https://www.baidu.com'

# 3.打开百度网页
webbrowser.open(url)

【终端输出】

True

【代码解析】

  1. webbrowser库名。

  2. 库名和函数之间有一个英文小圆点.

  3. open函数名。

  4. url是参数,即要打开的网页。

【返回值】

True

返回True表示打开网页成功。

【效果】

运行上面的代码,我的360浏览器会自动打开百度网站。如下图所示:

在这里插入图片描述

【调用模块或库中的函数语法】

调用模块或库的函数:模块名.函数名(),如 os.mkdir()

2.4 requests 库

requests 是第三方库,需要安装。

【pip安装requests库的方法】

  1. 打开命令行

在这里插入图片描述

  1. 在命令行中输入以下命令
pip install -i https://pypi.tuna.tsinghua.edu.cn/simple/ requests

【安装语法解析】

  1. 关键字pip

  2. 安装命令关键字install

install[ɪnˈstɔːl]:安装。

  1. -i后面表示要接的是镜像源。

  2. 下面的链接是清华大学镜像源。

https://pypi.tuna.tsinghua.edu.cn/simple/
  1. 要安装的库名:requests

【安装第3方库可参考下面的链接】

73. python第三方库安装教程(超详细)

【备注】

因为这个库我已经安装过了,这里不做图片展示。后面有安装的库图片展示,不懂的请参考后文。

【requests库的作用】

requests库的作用是发送HTTP请求,并处理响应。

它可以发送GET、POST、PUT、DELETE等请求,支持HTTPS、Cookie、Session等功能。

还可以处理JSON、XML等格式的数据。

requests 库简化了HTTP请求的操作,使得Python程序可以更方便地与Web服务器进行交互。

2.5 PySimpleGUI 库

PySimpleGUI 是第三方库,需要安装。

【pip安装库的代码】

pip install -i https://pypi.tuna.tsinghua.edu.cn/simple/ PySimpleGUI

安装过程如下图所示:

在这里插入图片描述

【GUI是什么】

GUI是Graphical User Interface的缩写,中文翻译为图形用户界面。

Graphical [ˈɡrafɪk(ə)l]:图形的。

Interface [ˈɪntəfeɪs]:接口。

它是一种通过图形化方式呈现计算机操作界面的技术,使得用户可以通过鼠标、键盘等输入设备与计算机进行交互。

GUI的出现使得计算机操作更加直观、易用,用户可以通过图形化的界面进行操作,而不需要记忆复杂的命令行指令。

常见的GUI包括Windows、Mac OS、Linux等操作系统的桌面界面。

【PySimpleGUI的作用】

PySimpleGUI是一个用于创建图形用户界面的 Python 库。

它提供了一种简单易用的方式来创建跨平台的 GUI 应用程序。

它的设计目标是让 GUI 开发变得简单、快速、易于理解和易于维护。

PySimpleGUI 支持多种 GUI 工具包,包括 Tkinter、Qt、WxPython 和 Pygame。

它可以用于创建各种类型的 GUI 应用程序,包括桌面应用程序、游戏、数据可视化工具等。

2.6 retrying库

retrying是第三方库,需要安装。

【pip安装库的代码】

pip install -i https://pypi.tuna.tsinghua.edu.cn/simple/ retrying

【retrying库的作用】

retrying:正在重试。

retrying库的作用是提供了一种简单的方式来添加重试逻辑,可以在函数执行失败时自动重试。

它可以帮助我们处理一些不稳定的操作,比如网络请求、数据库连接等,提高程序的健壮性和可靠性。

3. 源代码

上面的所有库都安装完成以后,就可以把下面的代码直接复制到py文件中。

然后点击运行。

import os
import tkinter as tk
import webbrowser
import requests
import tkinter.messagebox as mes_box
import PySimpleGUI as sg
from tkinter import ttk
from retrying import retry

class SetUI(object):
    """
    音乐弹框界面
    """
    def __init__(self, weight=1000, height=600):
        self.ui_weight = weight
        self.ui_height = height
        self.title = "好课优选·音乐破解软件"
        self.ui_root = tk.Tk(className=self.title)
        self.ui_url = tk.StringVar()
        self.ui_var = tk.IntVar()
        self.ui_var.set(1)
        self.show_result = None
        self.song_num = None
        self.response_data = None
        self.song_url = None
        self.song_name = None
        self.song_author = None

    def set_ui(self):
        """
        设置简易UI界面
        :return:
        """
        # Frame空间
        frame_1 = tk.Frame(self.ui_root)
        frame_2 = tk.Frame(self.ui_root)
        frame_3 = tk.Frame(self.ui_root)
        frame_4 = tk.Frame(self.ui_root)

        # ui界面中菜单设计
        ui_menu = tk.Menu(self.ui_root)
        self.ui_root.config(menu=ui_menu)
        file_menu = tk.Menu(ui_menu, tearoff=0)
        ui_menu.add_cascade(label='菜单', menu=file_menu)
        # file_menu.add_command(label='使用说明', command=lambda: webbrowser.open('www.baidu.com'))
        # file_menu.add_command(label='关于作者', command=lambda: webbrowser.open('www.baidu.com'))
        file_menu.add_command(label='退出', command=self.ui_root.quit)

        # 控件内容设置
        choice_passageway = tk.Label(frame_1, text='请选择音乐搜索通道:', padx=10, pady=10)
        # passageway_button_1 = tk.Radiobutton(frame_1, text='酷我', variable=self.ui_var, value=1, width=10, height=3)
        # passageway_button_2 = tk.Radiobutton(frame_1, text='网易云', variable=self.ui_var, value=2, width=10, height=3)
        # passageway_button_3 = tk.Radiobutton(frame_1, text='QQ音乐', variable=self.ui_var, value=3, width=10, height=3)
        # passageway_button_4 = tk.Radiobutton(frame_1, text='酷我', variable=self.ui_var, value=4, width=10, height=3)
        input_link = tk.Label(frame_2, text="请输入歌曲名或歌手:")
        entry_style = tk.Entry(frame_2, textvariable=self.ui_url, highlightcolor='Fuchsia', highlightthickness=1,
                               width=35)
        label2 = tk.Label(frame_2, text=" ")
        play_button = tk.Button(frame_2, text="搜索", font=('楷体', 11), fg='Purple', width=2, height=1,
                                command=self.get_KuWoMusic)
        label3 = tk.Label(frame_2, text=" ")
        # 表格样式
        columns = ("序号", "歌手", "歌曲", "专辑")
        self.show_result = ttk.Treeview(frame_3, height=20, show="headings", columns=columns)
        # 下载
        download_button = tk.Button(frame_4, text="下载", font=('楷体', 11), fg='Purple', width=6, height=1, padx=5,
                                    pady=5, command=self.download_music)

        # 控件布局
        frame_1.pack()
        frame_2.pack()
        frame_3.pack()
        frame_4.pack()
        choice_passageway.grid(row=0, column=0)
        # passageway_button_1.grid(row=0, column=1)
        # passageway_button_2.grid(row=0, column=2)
        # passageway_button_3.grid(row=0, column=3)
        # passageway_button_4.grid(row=0, column=4)
        input_link.grid(row=0, column=0)
        entry_style.grid(row=0, column=1)
        label2.grid(row=0, column=2)
        play_button.grid(row=0, column=3, ipadx=10, ipady=10)
        label3.grid(row=0, column=4)
        self.show_result.grid(row=0, column=4)
        download_button.grid(row=0, column=5)

        # 设置表头
        self.show_result.heading("序号", text="序号")
        self.show_result.heading("歌手", text="歌手")
        self.show_result.heading("歌曲", text="歌曲")
        self.show_result.heading("专辑", text="专辑")
        # 设置列
        self.show_result.column("序号", width=100, anchor='center')
        self.show_result.column("歌手", width=200, anchor='center')
        self.show_result.column("歌曲", width=200, anchor='center')
        self.show_result.column("专辑", width=300, anchor='center')

        # 鼠标点击
        self.show_result.bind('<ButtonRelease-1>', self.get_song_url)

    @retry(stop_max_attempt_number=5)
    def get_KuWoMusic(self):
        """
        获取酷我音乐
        :return:
        """
        # 清空treeview表格数据
        for item in self.show_result.get_children():
            self.show_result.delete(item)
        headers = {
            'accept': 'application/json, text/plain, */*',
            'accept - encoding': 'gzip, deflate',
            'accept - language': 'zh - CN, zh;q = 0.9',
            'cache - control': 'no - cache',
            'Connection': 'keep-alive',
            'csrf': 'HH3GHIQ0RYM',
            'Referer': 'http://www.kuwo.cn/search/list?key=%E5%91%A8%E6%9D%B0%E4%BC%A6',
            'User-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) '
                          'Chrome/99.0.4844.51 Safari/537.36',
            'Cookie': '_ga=GA1.2.218753071.1648798611; _gid=GA1.2.144187149.1648798611; _gat=1; '
                      'Hm_lvt_cdb524f42f0ce19b169a8071123a4797=1648798611; '
                      'Hm_lpvt_cdb524f42f0ce19b169a8071123a4797=1648798611; kw_token=HH3GHIQ0RYM'
        }
        search_input = self.ui_url.get()
        if len(search_input) > 0:
            search_url = 'http://www.kuwo.cn/api/www/search/searchMusicBykeyWord?'
            search_data = {
                'key': search_input,
                'pn': '1',
                'rn': '80',
                'httpsStatus': '1',
                'reqId': '858597c1-b18e-11ec-83e4-9d53d2ff08ff'
            }
            try:
                self.response_data = requests.get(search_url, params=search_data, headers=headers, timeout=20).json()
                songs_data = self.response_data['data']['list']
                if int(self.response_data['data']['total']) <= 0:
                    mes_box.showerror(title='错误', message='搜索: {} 不存在.'.format(search_input))
                else:
                    for i in range(len(songs_data)):
                        self.show_result.insert('', i, values=(i + 1, songs_data[i]['artist'], songs_data[i]['name'],
                                                               songs_data[i]['album']))
            except TimeoutError:
                mes_box.showerror(title='错误', message='搜索超时,请重新输入后再搜索!')
        else:
            mes_box.showerror(title='错误', message='未输入需查询的歌曲或歌手,请输入后搜索!')

    def get_song_url(self, event):
        """
        获取下载歌曲的地址
        :return:
        """
        # treeview中的左键单击
        for item in self.show_result.selection():
            item_text = self.show_result.item(item, "values")
            # 获取
            self.song_num = int(item_text[0])
        # 获取下载歌曲的地址
        if self.song_num is not None:
            songs_data = self.response_data['data']['list']
            songs_req_id = self.response_data['reqId']
            song_rid = songs_data[self.song_num - 1]['rid']
            music_url = 'http://www.kuwo.cn/api/v1/www/music/playUrl?mid={}&type=convert_url3' 
                        '&httpsStatus=1&reqId={}' 
                .format(song_rid, songs_req_id)
            response_data = requests.get(music_url).json()
            self.song_url = response_data['data'].get('url')
            self.song_name = songs_data[self.song_num - 1]['name']
            self.song_author = songs_data[self.song_num - 1]['artist']
        else:
            mes_box.showerror(title='错误', message='未选择要下载的歌曲,请选择')

    def download_music(self):
        """
        下载音乐
        :return:
        """
        if not os.path.exists('./KuWoMusic'):
            os.mkdir("./KuWoMusic/")
        if self.song_num is not None:
            song_name = self.song_name + '--' + self.song_author + ".mp3"
            try:
                save_path = os.path.join('./KuWoMusic/{}'.format(song_name)) 
                    .replace('\', '/')
                true_path = os.path.abspath(save_path)
                resp = requests.get(self.song_url)
                with open(save_path, 'wb') as file:
                    file.write(resp.content)
                    mes_box.showinfo(title='下载成功', message='歌曲:%s,保存地址为%s' % (self.song_name, true_path))
            except Exception:
                mes_box.showerror(title='错误', message='未找到存放歌曲的文件夹')
        else:
            mes_box.showerror(title='错误', message='未选择要下载的歌曲,请选择后下载')

    def progress_bar(self, file_size):
        """
        任务加载进度条
        :return:
        """
        layout = [[sg.Text('任务完成进度')],
                  [sg.ProgressBar(file_size, orientation='h', size=(40, 20), key='progressbar')],
                  [sg.Cancel()]]

        # window只需将自定义的布局加载出来即可 第一个参数是窗口标题。
        window = sg.Window('机器人执行进度', layout)
        # 根据key值获取到进度条
        _progress_bar = window['progressbar']
        for i in range(file_size):  # 循环
            event, values = window.read(timeout=10)
            if event == 'Cancel' or event is None:
                break
            _progress_bar.UpdateBar(i + 1)

    def ui_center(self):
        """
        UI界面窗口设置:居中
        """
        ws = self.ui_root.winfo_screenwidth()
        hs = self.ui_root.winfo_screenheight()
        x = int((ws / 2) - (self.ui_weight / 2))
        y = int((hs / 2) - (self.ui_height / 2))
        self.ui_root.geometry('{}x{}+{}+{}'.format(self.ui_weight, self.ui_height, x, y))

    def loop(self):
        """
        函数说明:loop等待用户事件
        """
        self.ui_root.resizable(False, False)  # 禁止修改窗口大小
        self.ui_center()  # 窗口居中
        self.set_ui()
        self.ui_root.mainloop()

if __name__ == '__main__':
    a = SetUI()
    a.loop()

4. 运行结果

代码正常运行后,得到如下一个GUI:

在这里插入图片描述

我把它称为vip音乐下载器。

5. 音乐下载器的使用

  1. 在【请输入歌曲名或歌手:】后面输入【张杰】。

  2. 点击【搜索】。

和张杰有关的所有歌曲会呈现在GUI界面上,如下图所示:

在这里插入图片描述

  1. 点击【下载】。

6. 去哪里找下载的音乐

我用vscode编辑器打开的是【安迪笔记】文件夹。

运行上面的代码后【安迪笔记】文件夹里多了一个【KuWoMusic】文件夹。

下载的音乐在【KuWoMusic】文件夹里。

在这里插入图片描述

vscode打开的是【安迪笔记】文件夹,下载的音乐在【安迪笔记】文件夹里的【KuWoMusic】文件夹里。

所以让大家重点关注下vscode打开的文件夹。

我衷心希望大家有空没空多研究下相对路径的知识,这个问题问我回答的头疼,太浪费我的时间了。

相对路径知识可参考如下链接。

68. Python的相对路径

7. 部分代码解析

【导入库语法】

import+模块名

import os
import requests
import webbrowser

【代码示例】

import tkinter as tk

【代码解析】

import tkinter as tk的作用是导入tkinter模块并将简写为tk

import PySimpleGUI as sg的作用是导入PySimpleGUI模块并将简写为sg

【代码示例】

import tkinter.messagebox as mes_box

【代码解析】

这行代码的意思是将 tkinter 库中的 messagebox 模块导入,并将其重命名为 mes_box。

这样就可以使用 mes_box 来调用 messagebox 模块中的函数,例如 mes_box.showinfo() 来显示一个信息框。

【代码示例】

from tkinter import ttk

【代码解析】

这行代码的意思是从 tkinter 模块中导入 ttk 子模块。

ttk 是 tkinter 的一个扩展模块,提供了一些额外的控件和样式选项。

【代码示例】

from retrying import retry

【代码解析】

从retrying库中导入retry函数。

代码解析先写库这个部分的。

其它代码后面有时间再解析吧。

真是困到怀疑人生了,今天的笔记没有检查,如果有错误、错别字大家联系我修改。

诶,一个不认真、不负责的博主!!!

8. 留言

源代码的作者是【湖南好课优选教育】的三更老师。

源代码是我上直播课写完作业后的奖励。

如涉侵权,请联系删除。

风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。