提示:仅供学习使用!
首先声明,我定义了几个全局变量,在开头提一嘴,以免后面看的难受:
list_end = []#用于储存音乐信息列表,后面将其放于listbox中
song_name = ''#音乐名字
先浅做一下GUI,我也是第一次学这个做的不好
def create_frame():
root = tk.Tk()
root.title("音乐下载器")
root.geometry('1000x600')
root.resizable(height=False,width=False)
l = Label(root,text = "音乐下载器",bg='#dde5ec',font=('Arial',12),width=15,height=2)
l.pack()
l2 = Label(root, text="请输入音乐名:", font=('Arial', 12), width=15, height=2).place(x=100,y = 90)
t = Entry(root)
t.place(x=250, y=100, width=600)
def get_song_name():
b1 = Button(root,text='搜索',command=get_song_name)
b1.place(x=860,y=98,height=24)
lb = Listbox(root,bg='#afb1b3',listvariable=var,borderwidth=5,font=('heiti',16))
def to_browser():
lb.place(x=180, y=140, height=400, width=600)
b2 = Button(root,text='跳\n转\n页\n面\n至\n网\n页',font=('Arial',12),bg='#dde5ec',command=to_browser).place(x=782,y=140,height=400,width=50)
root.mainloop()
分析需求,需要通过在Entry中输入音频名对其进行搜索,获取音频信息列表和音频链接
因此在搜索按钮b1点击时要触发指令获取音频名字,上面面代码中的get_song_name()中应写出以下代码:
global song_name,list_end
list_end.append('搜索中......')
song_name = t.get()
获取音频名之后,将名字传入函数get_song_list以获得音频列表,在上方代码后加上代码:
song_list = get_song_list(song_name=song_name)
获得的音频信息列表song_lsit,需要对其分别进行数据解析和抓取,这里通过一个函数insert_song对song_list分别处理得到信息列表和音频信息:
thread1 = threading.Thread(name='t1', target=insert_song(song_list))
thread1.Daemon = True
thread1.start()
由于是阻塞操作,在这里以多线程的方式执行,并将Daemon设置为True以保证子线程在主线程关闭后关闭。
下面给出上面用到的几个函数:
def get_song_list(song_name):
# 定义song_name储存歌曲名字
global list_end
list_end = ['搜索中......']
url = f"https://******/search-{song_name}.htm"
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.0.0 Safari/537.36'
}
response = requests.get(url=url, headers=headers)
response.encoding = "utf-8"
response = response.text
# 解析数据
html = etree.HTML(response)
song_list = html.xpath('//*[@id="body"]/div/div/div/div[2]/div[2]/ul/li')
return song_list
def insert_song(song_list):
for song in song_list:
global list_end
list_end.append(from_song_get_info(song)+'#'+from_song_get_url(song))
list_end.append('搜索完成')
由于listbox在放置后就无法用insert方法插入条目信息了,所以这里用list_end暂时存放,listbox用listvariable = var的方式,并定时更新var的值为list_end的值:
var = tk.StringVar()
#用定时器更新var值
var = updateVar(var=var)
def updateVar(var):
var.set(list_end)
threading.Timer(0.1,updateVar,(var,)).start()
return var
这样一来音频信息的增加和插入可以互相不冲突,同时进行。
由于上面b1的指令存在嵌套函数现象,担心阻塞主线程,故也采用多线程方式:
def get_song_name():
def zi():
global song_name,list_end
list_end.append('搜索中......')
song_name = t.get()
song_list = get_song_list(song_name=song_name)
thread1 = threading.Thread(name='t1', target=insert_song(song_list))
thread1.Daemon = True
thread1.start()
thread2 = threading.Thread(name='t2', target=zi)
thread2.Daemon = True
thread2.start()
我也不知道这样写有没有问题(我也没在别人那见过这样写的),如果有不妥之处,还希望大家指出。
这里再给出上面插入条目信息时使用到的函数:
def from_song_get_url(song):
detail_url = song.xpath('./div/div[1]/a/@href')[0]
detail_url = "https://www.hifini.com/" + detail_url
detail_html = requests.get(detail_url)
detail_html.encoding = "utf-8"
detail_html = detail_html.text
ed = "url: '(.*?)',"
findall = re.findall(ed, detail_html)
if len(findall)!= 0:
findall = findall[0]
else:
return "查无链接"
song_url = 'https://******/' + findall
return song_url
def from_song_get_info(song):
# 获取a标签下所有文本
info = "歌曲信息: " + song.xpath('./div/div[1]/a')[0].xpath('string(.)').strip()
return info
至此搜索解析操作完成。
下面在b2上添加指令to_browser,当我们选中一条音频信息时,点击按钮b2,帮助我们跳转到浏览器,可用于试听或下载。本来想用selenium实现,但考虑到浏览器版本问题,于是在这里使用cmd命令方式:
def to_browser():
def zi2():
song_url = lb.get(lb.curselection())
song_url = ''.join(song_url)
song_url = song_url.split('#')[1]
os.system('start ' + song_url)
if ''.join((lb.get(lb.curselection()))) != '查无链接' and ''.join((lb.get(lb.curselection()))) != '':
thread3 = threading.Thread(name='t3', target=zi2)
thread3.Daemon = True
thread3.start()
由于lb.get(lb.curselection())获得的是元祖形式的信息,没法用split方法分隔,因此首先用song_url = ‘’.join(song_url)转成字符串,随后可对其进行判断是否存在,如果存在则启动线程执行操作
就在我以为结束了的时候,发现了一个小问题:在跳转至浏览器时屏幕会闪过dos窗口,影响使用体验,在查找资料后,将os.system换成下面的代码:
os.popen('start ' + song_url)
这样就不会弹出dos窗口了,咱们的**也基本上大功告成了。
import requests
import os
import re
import threading
import time
import tkinter as tk
from tkinter import *
from lxml import etree
list_end = []
song_name = ''
def insert_song(song_list):
for song in song_list:
global list_end
list_end.append(from_song_get_info(song)+'#'+from_song_get_url(song))
list_end.append('搜索完成')
def get_song_list(song_name):
# 定义song_name储存歌曲名字
#song_name = 'hello'
global list_end
list_end = ['搜索中......']
url = f"https://www.hifini.com/search-{song_name}.htm"
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.0.0 Safari/537.36'
}
response = requests.get(url=url, headers=headers)
response.encoding = "utf-8"
response = response.text
# 解析数据
html = etree.HTML(response)
song_list = html.xpath('//*[@id="body"]/div/div/div/div[2]/div[2]/ul/li')
return song_list
def updateVar(var):
var.set(list_end)
threading.Timer(0.1,updateVar,(var,)).start()
return var
def create_frame():
root = tk.Tk()
root.title("音乐下载器")
root.geometry('1000x600')
root.resizable(height=False,width=False)
var = tk.StringVar()
#用定时器更新var值
var = updateVar(var=var)
l = Label(root,text = "音乐下载器",bg='#dde5ec',font=('Arial',12),width=15,height=2)
l.pack()
l2 = Label(root, text="请输入音乐名:", font=('Arial', 12), width=15, height=2).place(x=100,y = 90)
t = Entry(root)
t.place(x=250, y=100, width=600)
def get_song_name():
def zi():
global song_name,list_end
list_end.append('搜索中......')
song_name = t.get()
song_list = get_song_list(song_name=song_name)
thread1 = threading.Thread(name='t1', target=insert_song(song_list))
thread1.Daemon = True
thread1.start()
thread2 = threading.Thread(name='t2', target=zi)
thread2.Daemon = True
thread2.start()
b1 = Button(root,text='搜索',command=get_song_name)
b1.place(x=860,y=98,height=24)
lb = Listbox(root,bg='#afb1b3',listvariable=var,borderwidth=5,font=('heiti',16))
def to_browser():
def zi2():
song_url = lb.get(lb.curselection())
song_url = ''.join(song_url)
song_url = song_url.split('#')[1]
os.popen('start ' + song_url)
if ''.join((lb.get(lb.curselection()))) != '查无链接' and ''.join((lb.get(lb.curselection()))) != '':
thread3 = threading.Thread(name='t3', target=zi2)
thread3.Daemon = True
thread3.start()
lb.place(x=180, y=140, height=400, width=600)
b2 = Button(root,text='跳\n转\n页\n面\n至\n网\n页',font=('Arial',12),bg='#dde5ec',command=to_browser).place(x=782,y=140,height=400,width=50)
root.mainloop()
def from_song_get_url(song):
detail_url = song.xpath('./div/div[1]/a/@href')[0]
detail_url = "https://www.hifini.com/" + detail_url
detail_html = requests.get(detail_url)
detail_html.encoding = "utf-8"
detail_html = detail_html.text
ed = "url: '(.*?)',"
findall = re.findall(ed, detail_html)
if len(findall)!= 0:
findall = findall[0]
else:
return "查无链接"
song_url = 'https://www.hifini.com/' + findall
return song_url
def from_song_get_info(song):
# 获取a标签下所有文本
info = "歌曲信息: " + song.xpath('./div/div[1]/a')[0].xpath('string(.)').strip()
return info
if __name__ == '__main__':
create_frame()