python爬虫-GUI界面音乐下载器

首先整个结构分为爬虫代码和图形代码,两者结合就是完整的程序:

后面需要引入的包:

from tkinter import filedialog,scrolledtext,messagebox
from tkinter import *
import requests,json

爬虫部分:

这儿也是最难的,因为要找到真实链接地址,需要在很多的接口中去找,然后通过数据清洗找到需要的url,提取出来。这是整个代码中的精华,后期下载都是从这儿获取音乐的真实URL地址进行下载。

进入音乐官网搜索界面,打开F12开发者界面,可以看到搜索到的所有结果全部在这个接口里面

python爬虫-GUI界面音乐下载器_第1张图片

 爬虫代码里面运用request请求,请求这个接口,拿到你搜索到的所有数据,这儿还有一个请求参数,在headers里面查看,可以发现你要搜索的歌曲或者歌手都是请求参数发出去的

python爬虫-GUI界面音乐下载器_第2张图片

 写好整个请求参数后,就是对拿到的数据进一步处理

因为要找到歌曲的真实URL地址,花了我好多时间,不多说,直接上干货,因为这个请求时直接返回了音乐的真实url地址,而这个请求地址中唯一的变量就是rid后面的那串id,回到刚刚搜索拿到的所有数据,在里面刚好有rid,正好拿来用

python爬虫-GUI界面音乐下载器_第3张图片

 python爬虫-GUI界面音乐下载器_第4张图片

 python爬虫-GUI界面音乐下载器_第5张图片

 爬取的原理就是上面我说的那样,看起来页很简单,就是找这些数据要花点时间,不多说,直接上代码:

class Downloadmusic(object):
    Music_list = []
    Music_total = []
    def __init__(self):
        self.url = "http://www.kuwo.cn/api/www/search/searchMusicBykeyWord?"
        self.headers = {
            "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.135 Safari/537.36 Edg/84.0.522.63",
            "Cookie": "_ga=GA1.2.1083049585.1590317697; _gid=GA1.2.2053211683.1598526974; _gat=1; Hm_lvt_cdb524f42f0ce19b169a8071123a4797=1597491567,1598094297,1598096480,1598526974; Hm_lpvt_cdb524f42f0ce19b169a8071123a4797=1598526974; kw_token=HYZQI4KPK3P",
            "Referer": "http://www.kuwo.cn/search/list?key=%E5%91%A8%E6%9D%B0%E4%BC%A6",
            "csrf": "HYZQI4KPK3P"
        }
        self.args = {
            "key": UI.Music_se[0],
            "pn": UI.Page_num[-1], # 第几页
            "rn": "30",
            "httpsStatus": "1",
            "reqId": "cc337fa0-e856-11ea-8e2d-ab61b365fb50",
        }
        self.music_api = "http://www.kuwo.cn/url?format=mp3&rid={}&response=url&type=convert_url3" \
                    "&br=128kmp3&from=web&t=1598528574799&httpsStatus=1" \
                    "&reqId=72259df1-e85a-11ea-a367-b5a64c5660e5"
    # 获取歌曲信息
    def url_data(self):
        global number
        number = 1
        self.Music_list.clear()
        self.Music_total.clear()
        re = requests.get(url=self.url,headers=self.headers,params=self.args)
        re.encoding = "utf-8"
        Data = json.loads(re.text)['data']['list']
        music_datas = json.loads(re.text)['data']['total']
        self.Music_total.append(music_datas)
        for i in Data:
            try:
                rid = str(i['rid'])
                music_name = str(i['name'])
                music_actor = str(i['artist'])
                music_api = self.music_api.format(rid)
                music_url = requests.get(url=music_api)
                Music_url = json.loads(music_url.text)['url']
                self.Music_list.append(Music_url + "$" + music_name)
                music_mess.insert(END, " " + str(number) + ". " + music_name + 3 * " " + music_actor + "\n")
                music_mess.update()
                number += 1
            except:
                music_mess.insert(END," 该歌曲请求地址失败!!!" + "\n")

上方代码页很简单,就是一个请求拿到数据后,对数据进行一个处理,因为返回的是一个元组,所以需要把它转化一下,转换成json格式,这样好处理一点,然后通过循环把需要到的元素提取出来,真实的url地址也在这一步直接处理了,然后返回到一个列表中,要用到时直接从列表中取,精华部分说完了,那么该说下载了。

因为后面gui界面的操作原因,所以我把下载分为两种方式:

    def download_all(self):
        if UI.Folderpath == []:
            UI().alert()
        else:
            for i in self.Music_list:
                path="%s/%s.mp3" % (UI.Folderpath[0],i.split("$")[1])
                mess=requests.get(i.split("$")[0])
                with open(path,'wb') as f:
                    f.write(mess.content)
                mess_output.insert(END,i.split("$")[1] + 5*" " + "已下载成功!" + "\n")
                mess_output.update()

    # 单曲下载
    def download_single(self):
        if UI.Folderpath == []:
            UI().alert()
        else:
            if UI.Music_num[0] == '':
                mess_output.insert(0.0, " 请输入歌曲前面的正确序号!!!" + "\n")
            else:
                if int(UI.Music_num[0]) < 1 or int(UI.Music_num[0]) > number-1:
                    mess_output.insert(0.0, " 请输入歌曲前面的正确序号!!!" + "\n")
                else:
                    if 1 <= int(UI.Music_num[0]) <= number:
                        music = self.Music_list[int(UI.Music_num[0]) - 1].split("$")
                        path = "%s/%s.mp3" % (UI.Folderpath[0], music[1])
                        mess = requests.get(music[0])
                        with open(path, 'wb') as f:
                            f.write(mess.content)
                        mess_output.insert(END, " " + music[1] + 5 * " " + "已下载成功!" + "\n")
                    else:
                        pass

一个全部下载,一个单曲下载,下载页很简单,就是里面有很多的判断,没有这些判断的话后面的程序的bug有点多,这些就省略了,自己去看

接下来就是GUI部分、因为我也是才接触这个,也不是很了解,只能说一知半解,我也是在网上搜教程慢慢写的。不多说,写这个GUI用的是tkinter,这个是Python中一个GUI图形界面库,目前来说他是Python当中用的最多的图形操作界面。

为了方便管理代码块。所以这个也进行了封装

class UI(object):
    Music_se = []
    Folderpath = []
    Music_num = []
    Page_num = []
    def __init__(self):
        pass


    def main(self):
        global root
        root = Tk()
        self.args()
        self.lable()
        self.text()
        self.button()
        root.mainloop()

上面的这些创建的列表都是为了给爬取部分传递参数用的

可以看到,主要功能块分为 程序窗口参数设置、界面标签、文本输出框以及按钮控件,一个简单的程序主窗口就这样搭建起来了

下方是整个界面的详细参数:

    def args(self):
        root.title("music download")
        root.geometry("1200x700+350+200")
        root.resizable(width="False", height="False")
        root.configure(bg="#faebd7")


    def lable(self):
        lab1=Label(root, text="请先选择保存路径后再下载!!!", font=("宋体", 15), bg="#faebd7", fg="red")
        lab1.place(x="500", y="5")
        lab2=Label(root, text="请输入歌曲前方序号:", font=("宋体", 12), bg="#faebd7", fg="blue")
        lab2.place(x="480", y="105")


    def text(self):
        global mess_output,music_mess,search,music_num,page_num_show
        music_mess=scrolledtext.ScrolledText(root, font=("宋体", 15),relief=FLAT, fg="green")
        music_mess.place(height="500", width="450", x="100",y="150")
        mess_output=scrolledtext.ScrolledText(root, font=("宋体", 15), relief=FLAT, fg="green")
        mess_output.place(height="500", width="450", x="650", y="150")
        search=Entry(root,font=("宋体",15), relief=FLAT, fg="green")
        search.place(height="30", width="300", x="400", y="50")
        music_num=Entry(root,font=("宋体", 15), relief=FLAT, fg="green")
        music_num.place(height="30", width="60", x="640", y="100")
        page_num_show=Entry(root,font=("宋体", 15), relief=FLAT, fg="black", bg="#faebd7")
        page_num_show.place(height="30", width="50", x="845", y="100")



    def button(self):
        search = Button(root, text="搜索", bg="orchid", comman=lambda: (self.get_music(), Downloadmusic().url_data()))
        search.place(height="30", width="40", x="710", y="50")
        choose_path = Button(root, text="保存路径", bg="orchid", comman=self.path)
        choose_path.place(height="30", width="60", x="760", y="50")
        download_all = Button(root, text="全部下载", bg="orchid", comman=lambda: Downloadmusic().download_all())
        download_all.place(height="30", width="60", x="830", y="50")
        download_singe = Button(root, text="单曲下载", bg="orchid", comman=lambda: (self.get_num(), Downloadmusic().download_single()))
        download_singe.place(height="30", width="60",x="710",y="100")
        last_page = Button(root, text="上一页", bg="orchid", comman=self.last_page)
        last_page.place(height="30", width="60", x="780", y="100")
        next_page = Button(root, text="下一页", bg="orchid", comman=self.next_page)
        next_page.place(height="30", width="60", x="900", y="100")
        delete_mess=Button(root, text="清除信息", bg="orchid", comman=self.delete_message)
        delete_mess.place(height="30", width="60", x="900", y="50")


    # 获取搜索的音乐
    def get_music(self):
        Music = search.get()
        self.Music_se.clear()
        self.Music_se.append(Music)
        self.Page_num.append(1)
        music_mess.delete(0.0, END)
        page_num_show.delete(0, END)
        page_num_show.insert(0, str(1) + "页")

    # 获取输入的歌曲序号
    def get_num(self):
        MUSIC_NUM = music_num.get()
        self.Music_num.clear()
        self.Music_num.append(MUSIC_NUM)

    # 保存路径
    def path(self):
        folderpath = filedialog.askdirectory()
        self.Folderpath.clear()
        self.Folderpath.append(folderpath)
        mess_output.insert(0.0, " 音乐已保存在: " + folderpath + "\n")

    # 提示框
    def alert(self):
        messagebox.showinfo(title="提示",message="请选择保存路径后在下载!!!")
        self.path()

    #  清除信息
    def delete_message(self):
        mess_output.delete(0.0,END)

    # 下一页
    def next_page(self):
        if int(self.Page_num[-1]) <= int(Downloadmusic.Music_total[0]):
             self.Page_num.append(self.Page_num[-1] + 1)
             music_mess.delete(0.0, END)
             page_num_show.delete(0,END)
             page_num_show.insert(0, str(self.Page_num[-1]) + "页")
             Downloadmusic().url_data()
        else:
             pass

    # 上一页
    def last_page(self):
        if self.Page_num[-1] > 1:
             self.Page_num.append(self.Page_num[-1] - 1)
             music_mess.delete(0.0,END)
             page_num_show.delete(0,END)
             page_num_show.insert(0, str(self.Page_num[-1]) + "页")
             Downloadmusic().url_data()
        else:
             pass
if __name__ == "__main__":
     UI().main()

界面很简单,但是实际写出来还是有点小难度,七中涉及到运行逻辑,稍微不对就报错,光调试就用了一天,实在有点费脑,最烦的就是位置的一个调整,各种控件到底该在什么地方,多大合适,为了界面美化,可花费了一番功夫,还好做的不是很丑(个人觉得哈),如果大家认为丑那就没法了,个人审美也就这样。

下面是我的成品:

python爬虫-GUI界面音乐下载器_第6张图片

关于UI界面我也没啥可说的,因为我也是半懂状态,实在不会去网上搜tkinter相关的知识自己去了解哈

注:本文章旨在指导爬虫的分析以及编写代码过程,且该文章发表日期较为久远,原网站数据结构已经发生变动,爬取数据可能存在问题,所以直接拿来使用有问题,待作者有时间再来更新整个爬虫代码,敬请期待。。。。。

你可能感兴趣的:(爬虫,python,tkinter)