0.目录
1.分析页面
2.获取歌曲的id
3.获取歌曲信息
4.获取歌曲图片url
5.获取歌词
6.总结
7.完整代码
1.分析页面
这一次我们来爬取网易云音乐,爬取歌单内的所有歌曲的图片和歌词,最终的结果是我们只要输入歌单的id,我们就可以直接下载歌单内所有歌曲的图片和歌词,并且以自己想要的命名格式统一命名。
上图是这次的演示歌单,id为973185551。每个歌曲也是有对应的id,通过右键检查第一首歌曲,可以发现这首歌的id为1370008169。
进入歌曲页面,检查图片,会发现图片的url与id是看不出有一点关系的,也就是我们只能进入到歌曲的页面才能获得图片的url。
2.获取歌曲的id
注意:想要爬取真正的页面信息,必须将原url中的 /# 删除,否则无法通过url得到正确的源代码。
原本的歌单url:https://music.163.com/#/playlist?id=973185551
更改后的url:https://music.163.com/playlist?id=973185551
# encoding: utf-8
import requests
import re
import os
import json
# 获取网页源代码
def get_page(url):
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36'
}
response = requests.get(url, headers=headers)
return response.text
# 获得歌曲ID
def get_id(url_list):
text = get_page(url_list)
ids = re.findall(r, text, re.DOTALL)
return ids
def main():
url = 'https://music.163.com/playlist?id=973185551' # 歌单url
ids = get_id(url)
for id in ids:
print(id)
if __name__ == '__main__':
main()
运行的部分结果:
我们可以发现,我们已经提取出了歌单里所有歌的id。
3.歌曲信息
同样的,我们想要得到网页源代码,就必须将 /# 去掉,变为:
view-source:https://music.163.com/song?id=1370008169
我们可以直接获取meta下的信息
# 获取歌曲名
def get_name(url_song):
text = get_page(url_song)
song_name = re.findall(r'', text, re.DOTALL)
song_authors = re.findall(r'', text, re.DOTALL)
name = song_name[0] + ' - ' + song_authors[0]
return name
运行的部分结果:
4.获取歌曲图片url
歌曲图片的url也在一个meta标签下
# 获得歌曲图
def get_img(url_song):
text = get_page(url_song)
url_img = re.findall(r'', text, re.DOTALL)[0]
return url_img
运行的部分结果:
5.获取歌词
获取网易云音乐的歌词挺简单的,它们可以通过直接访问url获得。比如
http://music.163.com/api/song/lyric?id=1370008169&lv=1&kv=1&tv=-1
我们只需要改变id,就可以获得对应歌曲的歌词。
由于这一段信息是json格式,所以读取的时候可以使用json的方式直接获得歌词,并写入文件储存。
# 获取歌词
def get_lyric(id, name):
url_lyric = "http://music.163.com/api/song/lyric?id=" + id + "&lv=1&kv=1&tv=-1"
text = get_page(url_lyric)
judge_lyric = re.findall(r'{"nolyric":true,.*?}', text, re.DOTALL)
if judge_lyric:
print(str(name) + '无歌词\n')
else:
# 用json获取歌词
json_obj = json.loads(text)
initial_lyric = json_obj['lrc']['lyric']
root = "D://lyric//"
path = root + name + '.lrc'
try:
if not os.path.exists(root):
os.mkdir(root)
if not os.path.exists(path):
with open(path, 'w') as f:
f.write(initial_lyric)
f.close()
except:
return None
6.总结
当爬取网易云音乐的时候,网址出现的/#对我产生了很大的麻烦,白白浪费了三四个小时去修改我的访问方式,总在怀疑我是get用错了,又或者是headers写错了,对网页直接右键源代码也出现了问题。直到我去删除了网址中的/#,才正常的获得了源代码。使用正则去获取信息,主要是因为在获取简单的信息时,直接使用正则其实还是比较简单的,缺点是当歌曲变多后,使用正则会让程序执行速度变慢。
由于某些歌曲是无歌词的,所以我们需要添加判断是否有歌词的语句,否则会让程序在运行时报错。上图就是无歌词时,访问url的显示结果。偷懒一下,直接用正则匹配这一段,然后if判断时就会过,执行输出歌曲无歌词的提示,并让程序依旧正常运行。
7.完整代码
# encoding: utf-8
import requests
import re
import os
import json
# 获取网页源代码
def get_page(url):
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36'
}
response = requests.get(url, headers=headers)
return response.text
# 获得歌曲ID
def get_id(url_list):
text = get_page(url_list)
ids = re.findall(r, text, re.DOTALL)
return ids
# 获取歌曲名
def get_name(url_song):
text = get_page(url_song)
song_name = re.findall(r'', text, re.DOTALL)
song_authors = re.findall(r'', text, re.DOTALL)
name = song_name[0] + ' - ' + song_authors[0]
return name
# 获得歌曲图
def get_img(url_song, name):
text = get_page(url_song)
url_img = re.findall(r'', text, re.DOTALL)[0]
root = "D://pics//"
path = root + name + '.jpg'
try:
if not os.path.exists(root):
os.mkdir(root)
if not os.path.exists(path):
r = requests.get(url_img)
with open(path, 'wb') as f:
f.write(r.content)
f.close()
except:
return None
# 获取歌词
def get_lyric(id, name):
url_lyric = "http://music.163.com/api/song/lyric?id=" + id + "&lv=1&kv=1&tv=-1"
text = get_page(url_lyric)
judge_lyric = re.findall(r'{"nolyric":true,.*?}', text, re.DOTALL)
if judge_lyric:
print(str(name) + '无歌词\n')
else:
# 用json获取歌词
json_obj = json.loads(text)
initial_lyric = json_obj['lrc']['lyric']
root = "D://lyric//"
path = root + name + '.lrc'
try:
if not os.path.exists(root):
os.mkdir(root)
if not os.path.exists(path):
with open(path, 'w') as f:
f.write(initial_lyric)
f.close()
except:
return None
def main():
url = 'https://music.163.com/playlist?id=391228182' # 歌单url
ids = get_id(url)
names = []
fns_num = 1
num = len(ids)
for id in ids:
url_song = 'https://music.163.com/song?id=%s' % id
name = get_name(url_song)
get_img(url_song, name)
get_lyric(id, name)
names.append(name)
print("\r完成进度: {:.2f}%".format(fns_num * 100 / num), end="")
fns_num += 1
print('\n\n完成名单:')
for i in names:
print(i)
print('\n\n查找到的数量:' + str(num))
print('\n最终完成的数量:' + str(len(names)))
if __name__ == '__main__':
main()
运行的部分结果:
注:由于其中一首歌的名字出现“/”斜杠,导致文件无法储存,文件的命名格式是不能出现“/”。可以通过添加以下语句,将“/”转换成“、”。
s = "【贰婶/流浪的蛙蛙/HITA/冥月】世伪知贤 (用原创发声) - 贰婶、流浪的蛙蛙、HITA、冥月"
s = s.replace('/','、')