用python3爬取QQ音乐列表音乐

最近想爬取一些音乐来实战一下,选择了qq音乐

qq音乐明显的就是一个动态网页,所以需要抓包了。

不懂的关键词可利用好搜索引擎。

分析过程

在此就说说分析的大致过程吧。

先看看主页:

我们随便点开一个主题列表:

因为是动态网页,所以就在这里抓包吧,因为qq音乐是动态网页,需要相关的参数信息才能得到想要的音乐地址,随便以播放一首歌曲为例,如下图1中的歌曲ID,点进去这个看看,即点击播放按钮,发现来到了播放页面,打开我用的Chrome中的开发者工具,里面有我们想要的音乐地址(如下图2所示),图3展示得到列表歌曲的所有信息,需要编程清洗之后才能得到我们想要,在此会在下面的代码中标明。

  • 图1:

  • 图2:

  • 图3:

其中的URL地址,代码中会用到:

现在我们可能就会有思路出现了:抓包爬取列表的所有歌曲的ID号以及歌曲信息 –> 整合到以ID为基的html地址 –> 到播放页面利用beautiful模块爬取相关的音乐地址即可!so easy~

但经过我的测试说明,爬取播放页面的html信息是没有相关的音乐地址的,所以在得到歌曲ID信息,整合到以ID为基的html地址之后,我们还需要对播放页面进行抓包。下面说说如何在播放页面抓包。

先播放一首歌曲,再进行抓包,发现了这些信息(如下图1),再结合上面的音乐地址分析一下,发现了vkey信息的存在,即每一首歌的vkey信息是不同的,并且经过测试即便是同一个IDvkey也是一直不断自动变换着的,不过在测试之后可得出结论:只要得到vkey信息,再整合上面的音乐地址就能抓到音乐信息,并且经过代码编译之后下载下来。

特别说明一下,下载歌曲的地址以及我们抓包时的URL之中,仅仅有如vkey的不同,或者是一些ID的不同,其他的参数是相同的!所以我们才能仅仅抓到vkey信息就能方便的下载歌曲,就是这么个意思。不理解的朋友可细心观察一下。

  • 图1:

  • 图2:

其中的URL地址:


完整代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
'''
函数目标:
爬取QQ音乐列表音乐
编写时间:
2018-3-15
'''
import requests
import os
import time
import json
from urllib.request import urlretrieve
if __name__ == '__main__':
# 建立目录用于装爬取的音乐
if 'QQ音乐列表音乐' not in os.listdir():
os.makedirs('QQ音乐列表音乐')
'''
从URL中添加代理记忆必要的相关的参数以获取歌曲的ID以及歌曲名
'''
playlist_url = 'https://c.y.qq.com/qzone/fcg-bin/fcg_ucc_getcdinfo_byids_cp.fcg'
# 添加页面中的代理信息
header = {'user-agent':'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.186 Safari/537.36',
'cookie':'tvfe_boss_uuid=1770396a4ed2d111; pgv_info=ssid=s4189101616; pgv_pvid=7344469728; uin=; pgv_pvi=8737627136; pgv_si=s9378960384; _tucao_userinfo=ZU1hSHhlWVNPSnRoNWgwTjMzc2c4OVYzYjBuTkNjcDNHNjcyVkkzWm9WUkJZMWhxWDJ5SmpTSURFWDhVTk9TYkczU3JWc09EeEsrMEVnQ2RpK2FVNWh4M0x0Y21aOG5Vcms5MW9odmt6ZXNxRWlmeE9PZzM0SlQ1YmVuM0xhRVpUaWh5d2REV2FZcHdQdWdNL0daWE9rTTM0MlFjc1VoaHhNVkh4bkNqbnBOMDN2MG1sOEkxc0dYNFZRa24rd0RY--FeceGG8ErqgRGZz7WWwpsg%3D%3D; _tucao_session=WUVSc2RVVk95Y0ViU2NoNndsWmVlbzZoSG1WaFdpcEk4Q1M5bXZSTG9qanV3OEpuNVNQT3dBc0tBRERUY1NCRDZJek14Y2xYeFdmMWhiaWdkZ282UjdPdXVyT1ZYQnpCeG9BcklQUFBEMU5LQ3F3ajdmd3VWRmZ5QTJoN1ViS1krcEx0aUdUb3plckVNVGc3K0t2Z3pUeFJDcFZMNnU3dEpLUXZ5Zyt4dUpJdU5Hb3ZwZUhpTHM0OEhNQk0vcHJKN2tEOXVZay95WkFpZlFuSVBQZDhoSzlMVUMrVDQxN0llRzJuNkVWUGdTVjdyaVl2WVdscFlyVDJPald4MG9BWA%3D%3D--dDBBK5gXjLaGccOBzx4EBA%3D%3D; ts_refer=www.google.com/; ts_uid=3146042580; qqmusic_fromtag=66; yq_playdata=s; yqq_stat=0; yplayer_open=1; yq_index=0; yq_playschange=0; player_exist=1',
'referer':'https://y.qq.com/n/yqq/playlist/3766176211.html'}
# 添加参数信息,有些是非必须的,待研究,有兴趣的可以自己测试
paramter = {
'type':'1',
'json':'1',
'utf8':'1',
'onlysong':'0',
'disstid':'3766176211',
'format':'jsonp',
'g_tk':'5381', # 非必须
'jsonpCallback':'playlistinfoCallback', # 值可更改
'loginUin':'0',
'hostUin':'0',
'format':'jsonp',
"inCharset":'utf8',
'outCharset':'utf-8',
'notice':'0',
'platform':'yqq',
'needNewCode':'0',
}
playlist_re = requests.get(url=playlist_url, params=paramter, headers=header)
# 指定编码格式
playlist_re.encoding = 'utf-8'
# 改变为python可识别的json格式,进行必要的数据清洗,去掉前面的'jsonpCallback'部分
playlist_info = json.loads(playlist_re.text.lstrip('playlistinfoCallback(').rstrip(')'))
# 指定整体索引
playlist_info1 = playlist_info['cdlist'][0]
# 先存储歌手的姓名,观察可知,一共有19个索引,因为歌曲本身仅仅有20首,取前20个歌手名
singer_name = []
for num in range(0, 17):
singer_eainfo = playlist_info1['songlist'][num]
for each_info in singer_eainfo['singer']:
singer_name.append(each_info['name'])
num = 0
# 在循环体系中进行下一步的编写
for each in playlist_info1['songlist']:
'''
在获取歌曲vkey的主URL传入相关的参数得到相关的数据之后进行挖掘,得到vkey信息
其中的参数有些是不必要的,可自由修改,有些是必要的
'''
key_url = 'https://c.y.qq.com/base/fcgi-bin/fcg_music_express_mobile3.fcg'
# 传入相关的代理以及参数
header_1 = {'user-agent':'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.186 Safari/537.36',
'referer':'https://y.qq.com/portal/player.html',
'cookie':'tvfe_boss_uuid=1770396a4ed2d111; pgv_info=ssid=s4189101616; pgv_pvid=7344469728; uin=; pgv_pvi=8737627136; pgv_si=s9378960384; _tucao_userinfo=ZU1hSHhlWVNPSnRoNWgwTjMzc2c4OVYzYjBuTkNjcDNHNjcyVkkzWm9WUkJZMWhxWDJ5SmpTSURFWDhVTk9TYkczU3JWc09EeEsrMEVnQ2RpK2FVNWh4M0x0Y21aOG5Vcms5MW9odmt6ZXNxRWlmeE9PZzM0SlQ1YmVuM0xhRVpUaWh5d2REV2FZcHdQdWdNL0daWE9rTTM0MlFjc1VoaHhNVkh4bkNqbnBOMDN2MG1sOEkxc0dYNFZRa24rd0RY--FeceGG8ErqgRGZz7WWwpsg%3D%3D; _tucao_session=WUVSc2RVVk95Y0ViU2NoNndsWmVlbzZoSG1WaFdpcEk4Q1M5bXZSTG9qanV3OEpuNVNQT3dBc0tBRERUY1NCRDZJek14Y2xYeFdmMWhiaWdkZ282UjdPdXVyT1ZYQnpCeG9BcklQUFBEMU5LQ3F3ajdmd3VWRmZ5QTJoN1ViS1krcEx0aUdUb3plckVNVGc3K0t2Z3pUeFJDcFZMNnU3dEpLUXZ5Zyt4dUpJdU5Hb3ZwZUhpTHM0OEhNQk0vcHJKN2tEOXVZay95WkFpZlFuSVBQZDhoSzlMVUMrVDQxN0llRzJuNkVWUGdTVjdyaVl2WVdscFlyVDJPald4MG9BWA%3D%3D--dDBBK5gXjLaGccOBzx4EBA%3D%3D; ts_refer=www.google.com/; ts_uid=3146042580; qqmusic_fromtag=66; yq_playdata=s; yqq_stat=0; yq_index=0; yq_playschange=0; player_exist=1; ts_last=y.qq.com/n/yqq/playlist/3766176211.html; yplayer_open=1'}
paramter_1 = {
'g_tk':'5381', # 非必须
'jsonpCallback':'MusicJsonCallback', # 非必须,可更改
"loginUin":'0',
'hostUin':'0',
'format':'json',
'inCharset':'utf8',
'outCharset':'utf-8',
'notice':'0',
'platform':"yqq",
'needNewCode':'0',
'cid':'205361747', # 一致必须
'callback':'MusicJsonCallback', # 非必须,可更改
'uin':'0',
# 传入获取的信息
'songmid':each['songmid'],
'filename':'C400' + each['songmid'] + '.m4a',
'guid':'7344469728'
}
# 解析得到含有vkey的数据信息,然后进行清洗得到想要的信息
key_re = requests.get(url=key_url, params=paramter_1, headers=header_1)
# 指定编码格式
key_re.encoding = 'utf-8'
# 转换为python的json格式,进行简单的清洗
key_info = json.loads(key_re.text.lstrip('MusicJsonCallback(').rstrip(')'))
# 进一步的清洗
data_info = key_info['data']
items_info = data_info['items'][0]
print('数据采集完成,开始下载任务...')
# 接下来就是可以下载了
urlretrieve(url='http://dl.stream.qqmusic.qq.com/C4000041FwTv0Ai3Ku.m4a?vkey=' + items_info['vkey'] + '&guid=7344469728&uin=0&fromtag=66.mp3', filename='QQ音乐列表音乐/' + singer_name[num] + '-' + each['songname'] + '.mp3')
print('正在下载:' + singer_name[num] + '的' + each['songname'] + '!')
print('下载中....')
print('下载此歌曲完成!')
# 跳传到下一个歌手名
num = num + 1
time.sleep(1)
print('全部下载完成,请在本过程目录下查收!')

在使用urlretrieve函数时,其中的url参数输入时应当加上格式,如下载视频时加上.mp4,下载音乐时加上.mp3,否则会易出现HTTP 403 错误 – 禁止访问 (Forbidden)

最后

运行:

到目录查看:

一切还算是顺利。前段时间想爬取腾讯视频,研究了挺久,没有成功,还需要学习,腾讯的资源都在腾讯云上,我想方式都差不多。

后续说明

经过后来的测试,本代码爬取的思路还是正确的,但是爬取的信息流只能是同一个了…即便是不同的ID…

---------------本文终---------------

文章作者:刘俊

最后更新:2019年01月02日 - 14:01

许可协议: 转载请保留原文链接及作者。