小练一下实现音乐下载器

声明

该软件仅供学习和交流,该软件代码和测试早在2020 9 15 完成,在2020 9 17 上传博客致csdn.由于个别不良分子盗取博客,污染互联网环境。该博客于直接被csdn下架,现在本博主重新上传。此博客同时也将在本人的私人博客上上传(博客系统还在开发中)

目标需求

一.需求
1.实现一个歌曲的下载功能,并且可以下载一些VIP歌曲
2.拥有一个相对有好的GUI界面,便于与用户交互。
二 实现方法
	1.获取音乐。
		方案一:通过VIP实现音乐抓包实现下载功能。
		方案二:建立自己的音乐库
		方案三:通过VIP解析网站实现音乐下载(此方法最简单)
	2.用户交互界面
		1.通过pyqt开发一个炫酷的界面(难度较高)
		2.通过tkinter自带库开发一个界面较为简陋(最简单)
三 综合比较:
	使用1.方案三和2.2实现功能

软件效果预览

小练一下实现音乐下载器

小练一下实现音乐下载器
小练一下实现音乐下载器

小练一下实现音乐下载器

天气获取

这个没什么好说的很简单,至于代码讲解可以去参考我写的
python爬虫系列【3】的案例。

import urllib.request
import re
import tkinter.messagebox
import tkinter



'''这段代码来自于远古时代懒得去优化了'''
def get_weather():
    try:
        html = urllib.request.urlopen(r'http://www.weather.com.cn/weather/101240701.shtml')
        urllib.request.urlcleanup()
        read = html.read().decode('utf-8')
        def get_way(path,string):
            path_way=path
            path_get=re.compile(path_way)
            ture_key=path_get.findall(string,re.M)
            return str(ture_key)
        path_html='<input type="hidden" id="hidden_title" value=".*"'
        see_html=get_way(path_html,read)
        path_see='v.*°C'
        see_weather=get_way(path_see,see_html)
        day=get_way('.*日',see_weather).strip('[\"\']')
        weather=get_way('周.*°C',see_weather).strip('[\']')
        # print(weather)
        return weather
    except Exception as e:
        tkinter.messagebox.showinfo('tips', e)


# if __name__=="__main__":
#     weather=get_weather()
#     print(weather)

音乐获取

这个就是我们软件所涉及到的比较重要的功能。这里我选择了一个音乐解析网站
小练一下实现音乐下载器

抓包分析

打开开发者工具搜索歌曲我们可以看到服务器主要发送了三个请求如图;
小练一下实现音乐下载器
注意第一个箭头这是我们的第一个发送的请求网址,注意headers我们可以发现这是关于歌曲的一些信息。说明我们要先向其发送歌曲信息。
小练一下实现音乐下载器
再注意一下其内容我们可以发现它返回的是一个json数据包含歌曲链接

小练一下实现音乐下载器

小练一下实现音乐下载器
之后我们观察一下下面的网址,我们发现其是类似其他的来源的链接。
当然我们偷个懒只要第一个。
之后思路就简单了,发送歌曲通过data数据获取,之后获取歌曲链接之后访问禁止默认跳转302 之后获取音乐解析后的网址下载。
竟然如此下面上代码。

import requests
import os
import tkinter.messagebox
import tkinter
from urllib import request
class Music_get:
    '''可获取下载收费歌曲(网易云VIP)仅供学习和参考'''

    def __init__(self):
        self.session = requests.session()
        self.get_id='http://www.ciding.fun/'
        self.headers_id={
        'Accept': 'application/json, text/javascript, */*; q=0.01',
        'Accept-Encoding': 'gzip, deflate',
        'Accept-Language': 'zh-CN,zh;q=0.9',
        'Connection': 'eep-alive',
        'Content-Length': '65',
        'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',

        'Host': 'www.ciding.fun',
        'Origin': 'http://www.ciding.fun',
        'Referer': 'http://www.ciding.fun/?name=%E5%80%92%E5%B8%A6&type=netease',
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.81 Safari/537.36 SE 2.X MetaSr 1.0',
        'X-Requested-With': 'XMLHttpRequest'
    #首先不需要cookies只需要设置referer参数为构造后的网址
    #其次再data内设置input参数即可。
    #最后获取音乐的id再一次类推去访问解析服务器获取解析后的音乐的网址之后普下载
    }
        self.headers_music={
        'Accept': '*/*',
        'Accept-Encoding': 'identity;q=1, *;q=0',
        'Accept-Language': 'zh-CN,zh;q=0.9',
        'Connection': 'keep-alive',
        'Host': 'antiserver.kuwo.cn',
        'Range': 'bytes=0-',
        'Referer': 'http://www.ciding.fun/',
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.102 Safari/537.36'


    }


    def get_song_name(self,name):
        self.name=name
        data = {'input': self.name,
                'filter': 'name',
                'type': 'kuwo',
                'page': '1'}
        return data
    def get_url_song(self,name):
        try:

            self.data=self.get_song_name(name)
            self.frist_reason=self.session.post(url=self.get_id,headers=self.headers_id,data=self.data)
            self.music_root_web=self.frist_reason.json()['data'][0]['url']
            self.pic=self.frist_reason.json()['data'][0]['pic']
            self.title=self.frist_reason.json()['data'][0]['title']
            self.author=self.frist_reason.json()['data'][0]['author']
            # print(self.pic)
            # print(self.music_root_web)

            html_in=self.session.get(url=self.music_root_web,headers=self.headers_music,allow_redirects=False)
            self.music_url=html_in.headers['Location']
            # print(self.music_url)
            self.url_list=[]
            self.url_list.append(self.music_url)
            self.url_list.append(self.pic)
            self.url_list.append(self.title)
            self.url_list.append(self.author)
            # print(self.url_list)
            return self.url_list
        except Exception as e:
            tkinter.messagebox.showinfo('tips',e)
    def down_load(self,name,path):
        '''给出音乐的名称,已及mp3文件的下载地址需要给定后缀'''
        url=self.get_url_song(name)[0]
        self.file_path=path
        # music = requests.get(url=url)
        #
        # with open(self.file_path, 'wb') as f:
        #     f.write(music.content)
        #     f.close()
        request.urlretrieve(url,self.file_path)

        return self.file_path
    def play_music(self,path):
        if os.path.exists(path):
            os.system(path)
        else:
            print("输入的路径有误请重新检查")


if __name__=='__main__':


    get_music=Music_get()
    # music_name='十年'
    # path='十年.mp3'
    x=get_music.get_url_song('Wolves')
    print(x)






界面编写。

这个就没什么好说的了这里先说一下一些坑关于tkinter的
首先是tkinter的按钮绑定再类中的函数。首先再一个类里面的一个函数比如

def explme(self):
     pass
     

其中函数中的self是作为一个参数的所以为了符合语法需求我们必须使用lambda函数构造一个方法
lambda a:explme()
并且再按钮中的command和bind中是不一样的。


self.play_Button=tkinter.Button(self.win,image=self.image_play,compound = 'center',font=('宋体', 14),relief='groove',command=lambda :Root.function_load())
self.play_Button.place(x=420,y=250,width=150, height=140)
# self.play_Button.configure(image=img, compound="center")


self.tips=tkinter.StringVar()
self.tips.set('输入歌曲名称例如:十年')
self.Entry=tkinter.Entry(self.win,font=('宋体', 14),textvariable=self.tips,fg='gray')
self.Entry.place(x=10,y=52,width=400, height=30)
self.Entry.bind('<ButtonRelease-1>',func=lambda a:Root.click())
#lambda中的a变量没有实际作用目的是为了是语法合乎规范
#TypeError: <lambda>() takes 0 positional arguments but 1 was given
#由于在类中self是属于一个参数,所以为了接受只能使用a来接受



下面是完整代码;

'''创建一个霸气的UI界面,负责整个程序的架构'''
import os
import tkinter.filedialog
import tkinter
import requests
from PIL import Image,ImageTk
from weather import get_weather
import tkinter.messagebox
from Analyze_music import Music_get


class Root:
    def __init__(self):
        self.win = tkinter.Tk()
        self.win.geometry('600x475')
        self.win.title('VIP音乐下载器v0.55(测试版)')
        self.win.attributes('-toolwindow', True)
        self.win.resizable(width=False, height=False)



        self.path_b='inico\ground2.gif'
        self.image_b=tkinter.PhotoImage(file=self.path_b)
        self.canves = tkinter.Canvas(self.win,width=600,height=475)
        self.canves.create_image(0,100,image=self.image_b)
        self.canves.pack()

        self.exit='inico\exit'
        self.path_p=r'inico\download.gif'
        self.image_play=tkinter.PhotoImage(file=self.path_p)
        #要加载图标设个全局变量函数里面调用除外,在代码主体中需要设置全局
        self.path_go=r'inico\go.gif'
        self.image_go=tkinter.PhotoImage(file=self.path_go)

        self.path_s=r'inico\search.gif'
        self.image_s=tkinter.PhotoImage(file=self.path_s)


    def function_play(self):
        self.path_exit = 'inico\exit.txt'
        if not os.path.exists(self.path_exit):
            tkinter.messagebox.showinfo('tips','音乐还没有被下载呦')
        elif  os.path.exists(self.path_exit):
            f=open('inico\exit.txt','r')
            self.filename=f.read()
            f.close()
            tkinter.messagebox.showinfo('tips', '播放时将会在电脑上的播放器中播放\n若想返回软件请先退出播放软件')
            os.remove(self.path_exit)
            os.system(self.filename)




    def function_load(self):

        fun=Music_get()
        self.filename = tkinter.filedialog.askdirectory()
        self.filename = self.filename+'/'+self.music_name+".mp3"
        # print(self.filename)
        fun.down_load(self.music_name,self.filename)
        self.path_exit='inico\exit.txt'
        f=open(self.path_exit,'w')
        f.write(self.filename)
        f.close()
        tkinter.messagebox.showinfo('tips', '下载完成')



    def function_search(self):
        #搜索功能的方法
        #在函数里面的self.x只有在函数被执行后才可以在别的函数中使用

        self.view_picture = Image.open(r'inico\ground.jpg')
        self.img1 = ImageTk.PhotoImage(self.view_picture)
        self.info_view.configure(image=self.img1, compound="center", text='')
        self.info_view.update()

        self.info_view.configure(font=('宋体', 15), text='搜索中......\n部分歌曲可能搜索不到请谅解')
        self.info_view.update()
        self.music_name=self.Entry.get()
        need_s='输入歌曲名称例如:十年'
        if self.music_name==need_s:
            self.music_name='十年'
        get_list=Music_get()
        info=get_list.get_url_song(self.music_name)
        pic_view=get_list.get_url_song(self.music_name)[1]
        self.view_pic=r'inico\view.jpg'
        try:

            picture=requests.get(pic_view)
            with open(self.view_pic, 'wb') as f:
                f.write(picture.content)
                f.close()
            self.view_picture=Image.open(self.view_pic)
            self.img1 = ImageTk.PhotoImage(self.view_picture)
            self.info_view.configure(image=self.img1, compound="center", text='')
            self.info_view.update()
        except Image.UnidentifiedImageError:

            str_tips=info[2]+'\n'+info[3]
            print(str_tips)
            self.info_view.config(text=str_tips,font=('宋体', 14))
            self.info_view.update()





    def frame_parts(self):
        #天气显示框
        weather=get_weather()
        self.weather_label=tkinter.Label(self.win,text=weather,font=('宋体', 14))
        self.weather_label.place(x=0,y=0,width=600, height=40)

        #输入框
        self.tips=tkinter.StringVar()
        self.tips.set('输入歌曲名称例如:十年')
        self.Entry=tkinter.Entry(self.win,font=('宋体', 14),textvariable=self.tips,fg='gray')
        self.Entry.place(x=10,y=52,width=400, height=30)
        self.Entry.bind('<ButtonRelease-1>',func=lambda a:Root.click())
        #lambda中的a变量没有实际作用目的是为了是语法合乎规范
        #TypeError: <lambda>() takes 0 positional arguments but 1 was given
        #由于在类中self是属于一个参数,所以为了接受只能使用a来接受

        #搜索按钮
        self.search=tkinter.Button(self.win,image=self.image_s,compound = 'center',font=('宋体', 14),relief='groove',command=lambda :Root.function_search())
        self.search.place(x=420,y=52,width=150, height=35)

        #歌曲信息预览
        self.info_view=tkinter.Label(self.win,font=('宋体', 10),relief='groove')
        self.info_view.place(x=10,y=86,width=400, height=328)

        #联系作者
        self.link_ant=tkinter.Button(self.win,text='作者详情',font=('宋体', 13),relief='groove',command=lambda :Root.link_command())
        self.link_ant.place(x=447 ,y=417,width=150,height=50)

        #播放按钮
        self.play_Button=tkinter.Button(self.win,image=self.image_go,compound = 'center',font=('宋体', 14),relief='groove',command=lambda :Root.function_play())
        self.play_Button.place(x=420,y=150,width=135, height=43)

        #下载按钮


        self.play_Button=tkinter.Button(self.win,image=self.image_play,compound = 'center',font=('宋体', 14),relief='groove',command=lambda :Root.function_load())
        self.play_Button.place(x=420,y=250,width=150, height=140)
        # self.play_Button.configure(image=img, compound="center")


    def link_command(self):
        tkinter.messagebox.showinfo('tips', '软件失效请联系作者\n作者QQ:3139541502\n该软件仅供学习和交流请勿用作商务\n若产生纠纷与作者无关!!!')
    def click(self):
        self.tips.set('')
        self.Entry.config(fg='black',textvariable=self.tips)



    def mainloop(self):
        self.win.mainloop()




if __name__=="__main__":
    Root=Root()
    Root.frame_parts()
    Root.mainloop()


资源文件

整个项目中是有一些资源文件的比如那些按钮中的贴图。
小练一下实现音乐下载器

项目获取

小练一下实现音乐下载器
链接:https://pan.baidu.com/s/1p4nJNGjIEogtHiVQ3CdzvQ
提取码:hve6

上一篇:27 Sqlite命令行


下一篇:【转】MYSQL入门学习之一:基本操作