-
Notifications
You must be signed in to change notification settings - Fork 9
/
Music__QQ.py
286 lines (261 loc) · 10.1 KB
/
Music__QQ.py
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
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
#!bin/even/python3.6
# -*- encoding:utf-8 -*-
# author:pzq
import requests
import os
import re
import json
from requests import RequestException
from multiprocessing import Pool
from lxml import etree
"""
'http://dl.stream.qqmusic.qq.com/' 这个网站结合从歌曲信息获取到的purl进行拼接 就可以得到播放的地址然后对内容进行下载
参数信息:
purl
歌曲的播放地址用上述的拼接进行获取
http://dl.stream.qqmusic.qq.com/C400002CJIg01yHquI.m4a?guid=8874756349&vkey=A3B648A1F511D4064C57684BF64F8FCBBA87ED01422023D2BF20110B8D7E18D25009BA93268E7334E133B0A113361EB777CCCE1F9A8E9965&uin=0&fromtag=66
获取purl信息的url地址:https://u.y.qq.com/cgi-bin/musicu.fcg?
参数:
-: getplaysongvkey3736817870528528
g_tk: 5381
loginUin: 0
hostUin: 0
format: json
inCharset: utf8
outCharset: utf-8
notice: 0
platform: yqq.json
needNewCode: 0
data: {"req_0":{"module":"vkey.GetVkeyServer","method":"CgiGetVkey","param":{"guid":"8874756349","songmid":["003XCbA520zgXW"],"songtype":[0],"uin":"0","loginflag":1,"platform":"20"}},"comm":{"uin":0,"format":"json","ct":24,"cv":0}}
-: getplaysongvkey15410530308016956
g_tk: 5381
loginUin: 0
hostUin: 0
format: json
inCharset: utf8
outCharset: utf-8
notice: 0
platform: yqq.json
needNewCode: 0
data: {"req_0":{"module":"vkey.GetVkeyServer","method":"CgiGetVkey","param":{"guid":"8874756349","songmid":["000zmYjO01BWe2"],"songtype":[0],"uin":"0","loginflag":1,"platform":"20"}},"comm":{"uin":0,"format":"json","ct":24,"cv":0}}
https://c.y.qq.com/qzone/fcg-bin/fcg_ucc_getcdinfo_byids_cp.fcg? 这个是歌曲信息的url
参数信息:
'type': '1',
'json': '1',
'utf8': '1',
'onlysong': '0',
'disstid': '6796775368',
'g_tk': '5381',
'loginUin': '0',
'hostUin': '0',
'format': 'json',
'inCharset': 'utf8',
'outCharset': 'utf - 8',
'notice': '0',
'platform': 'yqq.json',
'needNewCode': '0',
https://c.y.qq.com/splcloud/fcgi-bin/fcg_get_diss_by_tag.fcg? 这个是歌单的url 先获取20个歌单 在对每个歌单的歌曲进行进行解析就可以获的到所有的歌曲信息
参数信息:
picmid: 1
rnd: 0.59461213653597
g_tk: 5381
loginUin: 0
hostUin: 0
format: json
inCharset: utf8
outCharset: utf-8
notice: 0
platform: yqq.json
needNewCode: 0
categoryId: 10000000
sortId: 5
sin: 0
ein: 19
"""
class QQMusic:
def __init__(self):
"""
header_origin: play list header
header_song: songs list header
header_download: down_load songs header
download_url: download url to download songs
"""
header_origin = {
# 'referer': 'https://www.pearvideo.com/category_8',
'Referer': 'https://y.qq.com/portal/playlist.html',
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36',
}
header_song = {
# 'referer': 'https://www.pearvideo.com/category_8',
'Referer': 'https://y.qq.com/portal/player.html',
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36',
}
header_download = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36',
}
download_url = 'http://isure.stream.qqmusic.qq.com/'
song_info_url = 'https://u.y.qq.com/cgi-bin/musicu.fcg?'
self.song_info_url = song_info_url
self.header_song = header_song
self.header_origin = header_origin
self.download_url = download_url
self.header_download = header_download
def parse_origin(self):
"""
parse the origin url get the album of id to song's list
the part of data should to put the def __init__()
:return:
"""
url = 'https://c.y.qq.com/splcloud/fcgi-bin/fcg_get_diss_by_tag.fcg?'
data = {
'picmid': '1',
'rnd': '',
'g_tk': '5381',
'loginUin': '0',
'hostUin': '0',
'format': 'json',
'inCharset': 'utf8',
'outCharset': 'utf-8',
'notice': '0',
'platform': 'yqq.json',
'needNewCode': '0',
'categoryId': '10000000',
'sortId': '5',
'sin': '0',
'ein': '19',
}
try:
response = requests.get(url, params=data, headers=self.header_origin)
if response.status_code == 200:
self.get_album_id(response.text)
except RequestException:
print('Response wrong!')
def get_album_id(self, content):
"""
from play of html to get play of id information, put this information in group, so that i can use the multiprocessing
this method can accelerate crawl speed
:param content: origin html's content
:return:
"""
grounds = []
infos = json.loads(content)
ids = infos.get('data').get('list')
for id_in in ids:
id = id_in.get('dissid')
grounds.append(id)
# here to open some pool use the number information
self.pool_function(grounds)
def pool_function(self, group):
"""
excess and start pool
:param group: id grounds, according to this group of number to pass the parse function and to get the play list id
:return:
"""
pool = Pool(5)
pool.map(self.parse_song_id, group)
def parse_song_id(self, id):
"""
get play menu's id and get songs information
:param id: everyone play menu of id can gain every songs information
:return:
"""
header_song_list = {
'Referer': 'https://y.qq.com/n/yqq/playsquare/' + str(id) + '.html',
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36',
}
base_url = 'https://c.y.qq.com/qzone/fcg-bin/fcg_ucc_getcdinfo_byids_cp.fcg?'
"""唯一的不同在于disstid disstid就是我需要获取的歌单id"""
data = {
'type': '1',
'json': '1',
'utf8': '1',
'onlysong': '0',
'disstid': str(id),
'g_tk': '5381',
'loginUin': '0',
'hostUin': '0',
'format': 'json',
'inCharset': 'utf8',
'outCharset': 'utf - 8',
'notice': '0',
'platform': 'yqq.json',
'needNewCode': '0',
}
try:
response = requests.get(base_url, params=data, headers=header_song_list)
if response.status_code == 200:
self.parse_songs_info(response.text)
except RequestException:
print('Response songs list is wrong!')
def parse_songs_info(self, content):
"""
get menu's of information parse every html get songmid: in order to get vkey and get start download songs
:param content: every html information and get id start
:return:
"""
infos_ = json.loads(content)
infos = infos_.get('cdlist')[0].get('songlist')
for info in infos:
song_mid = info.get('songmid')
song_name = info.get('songname')
self.parse_song((song_mid, song_name))
def parse_song(self, song_info):
"""
song_info is list id is the first param
:param song_info: including sond_mid and song_name to get songs content and start download
:return:
"""
data = {
'g_tk': '5381',
'loginUin': '0',
'hostUin': '0',
'format': 'json',
'inCharset': 'utf8',
'outCharset': 'utf - 8',
'notice': '0',
'platform': 'yqq.json',
'needNewCode': '0',
'data': '{"req_0":{"module":"vkey.GetVkeyServer","method":"CgiGetVkey","param":{"guid":"8874756349","songmid":["' + song_info[0] + '"],"songtype":[0],"uin":"0","loginflag":1,"platform":"20"}},"comm":{"uin":0,"format":"json","ct":24,"cv":0}}',
}
try:
response = requests.get(self.song_info_url, params=data, headers=self.header_song)
if response.status_code == 200:
self.parse_play_id(response.text, song_info)
except RequestException:
print('Song response is wrong!')
def parse_play_id(self, content, song_info):
"""
get purl it's include vkey and other params and begin download
:param content: get play html and get purl because this param can direct get songs information
:param song_info: is list id is the first param name is the second param
:return:
"""
info = json.loads(content)
part_url = info.get('req_0').get('data').get('midurlinfo')[0].get('purl')
try:
response = requests.get(self.download_url + part_url, headers=self.header_download)
if response.status_code == 200:
self.store_song(response.content, song_info[1])
except RequestException:
print("Song response is wrong!")
def store_song(self, content, song_name):
"""
store songs to file
:param content: song's information
:param song_name: filename use every song's name as file name
:return:
"""
try:
print("正在下载:{0}".format(song_name))
path_store = r'..\videos\{0}.{1}'.format(song_name, 'm4a')
if not os.path.exists(path_store):
with open(path_store, 'wb') as f:
f.write(content)
f.close()
except OSError:
print("writing songs:{0} is wrong!".format(song_name))
def start_function(self):
self.parse_origin()
if __name__ == '__main__':
qq_music = QQMusic()
qq_music.start_function()