我们之前已经学习了selenium的简单实用,现在就来实战下,我们通过selenium获取歌曲的id,然后通过网易云音乐的外链地址来下载音乐,做一个音乐下载器(此项目仅供教学使用),下面我们先来看一下效果:
老规矩,我们先来分析下这个音乐下载器的构成:
- 通过输入框输入我们需要搜索的歌曲
- 点击“搜索”按钮实现对歌曲的搜索
- 在列表框里选择想要下载的音乐,点击“下载”按钮即可下载
- 点击“退出”按钮,实现软件的退出
首先我们先把软件的界面先做出来:
from tkinter import *
window = Tk()
window.geometry('300x500')
window.title('音乐下载器')
Label(window,text='请输入你想搜索的音乐:',font=('楷体',12)).place(x=10,y=10)
# 输入框
key_word = Entry(window,width=25,font=('楷体',16))
key_word.place(x=10,y=30)
# 搜索按钮
def search():
pass
Button(window,text='搜索',width=5,height=1,font=('楷体',16),command=search).place(x=10,y=70)
# 下载按钮
def download():
pass
Button(window,text='下载',width=5,height=1,font=('楷体',16),command=download).place(x=115,y=70)
# 退出按钮
Button(window,text='退出',width=5,height=1,font=('楷体',16),command=quit).place(x=222,y=70)
# 显示搜索内容的列表框
show = Listbox(window,width=25,height=16,font=('楷体',16))
show.place(x=10,y=120)
window.mainloop()
接下来我们就要实现功能了,我们一起来分析一下网页:
- 我们访问的对象是网易云音乐https://music.163.com/#/search/m/:
我们可以看见,网易云音乐的搜索地址有两个参数,s对应的是搜索的内容,type类型,这里指的应该是单曲还是歌手还是其他的模式,那么我们直接搜索单曲就好了,变量就是歌名这一个,直接拼接就好; - 接下来我们看一下下面歌曲对应的代码:
我们看见1号位置的就是我们需要的东西,有了歌曲的id,就可以通过外链链接来下载音乐了;那么我们想要找到这部分内容,需要进行定位,最开始想直接通过class标签进行定位,但是死活搜索不到,后面发现这部分内容是在frame框架里面的,就是我们2号位置,所以我们需要先定位到这个框架里面,然后再对内容进行匹配; - 接下来我们就要获取所有音乐的信息了
我们发现所有的歌曲信息都是保存在这样的class标签里面的,我们直接通过class标签搜索就好了,但是会发现有两种,隔一个变一下,所以我们需要将信息提取两次(中间也想过合并条件进行搜索,但是失败了,不知道是不是写法有问题,如果有可行的方法,欢迎指导); - 获取所有的歌曲信息后,就要对每首歌的信息分别进行提取和存储:
这三个地方就是我们需要的信息,搜索的方法有很多,我这边还是习惯xpath,这个可以根据自己的习惯来,都能实现效果,将信息都提取出来之后,需要对信息进行存储; - 将所有信息都提取出来之后,我们对这三项数据进行打包,供我们后面使用;
好了,现在怎么抓取数据我们也知道了,接下来我们就敲代码实现数据提取的功能:
from selenium import webdriver # 导入库
def get_music_info(key_word): # 我们将获取歌曲的名字、id和歌手
chrome_options = webdriver.ChromeOptions() # 接下来三行是定义浏览器的设置,实现无界面浏览器
chrome_options.add_argument('--headless') # 因为搜索操作是后台操作,省去界面效率将更高
chrome_options.add_argument('--disable-gpu')
driver = webdriver.Chrome(chrome_options=chrome_options) # 创建浏览器对象
url = 'https://music.163.com/#/search/m/?s={}'.format(key_word) # 合成搜索地址
driver.get(url) # 发出访问请求
driver.switch_to.frame('g_iframe') # 获取frame框架内容
# 用xpath的方式获取所有歌曲的全部信息
data_all = driver.find_elements_by_xpath('.//div[@class="item f-cb h-flag "]')
data_all += driver.find_elements_by_xpath('.//div[@class="item f-cb h-flag even "]')
id_ = [] # 保存歌曲的id
name = [] # 保存歌曲的名字
author = [] # 保存歌手的名字
for data in data_all: # 遍历所有歌曲的信息
# 因为我们只需要id就好,所以这里需要进一步字符串切割
id_.append(data.find_element_by_xpath('.//div[@class="td w0"]//a').get_attribute('href').split('=')[1])
# 提取歌曲名称
name.append(data.find_element_by_xpath('.//div[@class="td w0"]//b').get_attribute('title'))
# 提取歌手名称
author.append(data.find_element_by_xpath('.//div[@class="td w1"]//a').text)
return list(zip(name,author,id_)) # 将数据打包
print(get_music_info('沙漠骆驼')) # 这里只做测试用
# 输出结果:
# [('沙漠骆驼', '展展与罗罗', '486814412'), ('沙漠骆驼 (伴奏)', '展展与罗罗', '1320097149'), ('沙漠骆驼(女生版)(Cover:展展与罗罗)', '澪恩Seiwen', '1317952370'), ('沙漠骆驼', '李传胜', '1336778074'), ('沙漠骆驼(女声版)(Cover:展展与罗罗)', '花僮', ……
这边我直接写了一个方法,后面我们直接调用就好,后期可以把这个整成类,搜索和下载做在一块;
我们来看一下搜索按钮对应的代码该怎么写:
info = [] # 存储返回的搜索结果
def search():
global info # 导入全局变量
key = key_word.get() # 获取输入框的内容
info = get_music_info(key) # 调用方法,对歌曲信息进行搜索
for i in range(show.size()): # 清除列表内容
show.delete(0)
for data in info: # 将歌曲信息显示在列表上面
show.insert('end', '{}({})'.format(data[0], data[1])) # 直接显示歌名和歌手就好
Button(window,text='搜索',width=5,height=1,font=('楷体',16),command=search).place(x=10,y=70)
最后就是对下载的实现了,我们在上面已经获取了歌曲的id,我们可以通过外链地址下载音乐(至于什么是外链,自行百度):
def download():
global info # 导入全局变量
index = show.curselection()[0] # 获取列表中选中的index
tmp = info[index] # 将歌曲的信息提取出来
url = 'https://link.hhtjim.com/163/{}.mp3'.format(tmp[2]) # 合成下载链接
data = requests.get(url).content # 获取歌曲的二进制数据
with open('{}({}).mp3'.format(tmp[0],tmp[1]),'wb') as f: # 保存歌曲
f.write(data)
Button(window,text='下载',width=5,height=1,font=('楷体',16),command=download).place(x=115,y=70)
到这里,我们的音乐下载器就做完了,下面附上源码:
from get_music_info import * # 这个是搜索歌曲信息的方法所在的文件
from tkinter import *
import requests
window = Tk()
window.geometry('300x500')
window.title('音乐下载器')
Label(window,text='请输入你想搜索的音乐:',font=('楷体',12)).place(x=10,y=10)
key_word = Entry(window,width=25,font=('楷体',16))
key_word.place(x=10,y=30)
info = []
def search():
global info
key = key_word.get()
info = get_music_info(key)
for i in range(show.size()):
show.delete(0)
for data in info:
show.insert('end', '{}({})'.format(data[0], data[1]))
Button(window,text='搜索',width=5,height=1,font=('楷体',16),command=search).place(x=10,y=70)
def download():
global info
index = show.curselection()[0]
tmp = info[index]
url = 'https://link.hhtjim.com/163/{}.mp3'.format(tmp[2])
data = requests.get(url).content
with open('{}({}).mp3'.format(tmp[0],tmp[1]),'wb') as f:
f.write(data)
Button(window,text='下载',width=5,height=1,font=('楷体',16),command=download).place(x=115,y=70)
Button(window,text='退出',width=5,height=1,font=('楷体',16),command=quit).place(x=222,y=70)
show = Listbox(window,width=25,height=16,font=('楷体',16))
show.place(x=10,y=120)
window.mainloop()