爬取虾米音乐
程序员文章站
2022-04-19 19:36:31
...
在网页版的虾米音乐播放器,如何下载音乐。
本次爬虫使用的语言是python3,模块是requests。笔者只是简单的示例,程序中还有许多需要改进的地方。
1、虾米音乐的播放器地址:http://www.xiami.com/play?ids=/song/playlist/id/1774747126#loaded
2、浏览器(笔者使用的是360极速浏览器),右键——审查元素,打开开发者工具。进入network中的XHR,网页歌曲信息是动态加载的。记得要重新刷新网页,才会出现左侧的文件。找到如下图的文件。这个不是标准的json文件。把Response中的代码,复制出来,进行观察,会发现把json378()去掉之后,就是一个标准的json文件。笔者没有用代码处理这一步。
3、具体思路是:大家可以用requests访问以下网页:
-
Request URL:http://www.xiami.com/song/playlist-default/cat/json?_ksTS=1511418676536_377&callback=jsonp378
-
然后req.text,再使用strip()函数去掉json378()。就可以得到json文件。再使用json.loads() 提取出location。大家可以使用在线json解析工具,先查找一下。
-
音乐的具体网址是隐藏在location的字典里面:如下图所示:
-
4、笔者是直接复制出location,才开始分析。
首先分析一下location,肯定经过加密,不会轻易得到音乐的下载链接url。笔者于是,上网查找资料,在这里要感谢cwyalpha。
他的博客文章有讲到如何解密出MP3文件地址。文章链接:http://blog.csdn.net/cwyalpha/article/details/48110941,大家可以参考一下。
例如:这个location是:
8h28n2325%%5_Fy955f6df3tF.e%%FE258la%2EEba5%t%xt2521FE8.u34--4c85p2i%FE19143mtD4%4cd5E%Fa268%2796ph1%58f%6%3mmF31517533_55E13575A1i842E2464%k1E-edEeE%2.15%%87_43e1%%96836
8代表把location分成8行,如何分。经笔者观察主要按'h','t','t','p','%','3','A','%','2','F','%','2','F','m'这些字符进行分行,因为MP3的下载链接,前面都是http://m128.xiami.net域名。还有,注意的是每一行的长度都是差不多,所以有重复的分割字符,需要往后寻找分割字符,尽量与第一行长度一样。最后,自己可以计算一下,location总共多少个字符,再除以8行,这样就知道一行大概有多少字符。
所以笔者的分法如下:
8
h28n2325%%5_Fy955f6df3
tF.e%%FE258la%2EEba5%
t%xt2521FE8.u34--4c85
p2i%FE19143mtD4%4cd5E
%Fa268%2796ph1%58f%6%
3mmF31517533_55E13575
A1i842E2464%k1E-edEeE
%2.15%%87_43e1%%96836
如何用代码进行分割字符,笔者想法比较简单,我会计算两个分割字符的位置,来进行分割。应该还有更好的分割方法。
5、从上往下一直组合,如下图所示,得到location的url编码:笔者的代码实现是:以第一行字符串长度为准,第一行字符串长度-第二行字符串长度,得到的差值,就表明需要补齐几个‘*’ 号。当然,大家可以使用其他字符,并且里面不会出现的字符,例如加号等。笔者此举是要保持行数的字符个数一致,便于使用zip()函数,同时取出同一列的字符。
组合成url。最后用replace方法,把‘*’ 号,用空字符代替。
6、使用urllib模块的 parse.unquote()方法解码,会出现‘^’字符,把‘^’字符变为‘0’字符,这样就可以得到真正的url。
mix_url=urllib.parse.unquote(mix_url).replace('^','0')
7、用requests模块访问url,with open写入文件到电脑中
8、具体代码如下:
import urllib
import os
import requests #下载虾米音乐 dream it possible 下载地址在json文件location
split_char=['h','t','t','p','%','3','A','%','2','F','%','2','F','m'] #分割字符标志
#location
raw_url='8h28n2325%%5_Fy955f6df3tF.e%%FE258la%2EEba5%t%xt2521FE8.u34--4c85p2i%FE19143mtD4%4cd5E%Fa268%2796ph1%58f%6%3mmF31517533_55E13575A1i842E2464%k1E-edEeE%2.15%%87_43e1%%96836'
max_num=len(raw_url)//int(raw_url[0])+1 #max_num=22 计算一行可以包含多少个字符
new_url=raw_url[1:] #去掉行数8
name=[] #创建8个list
for k in range(1,int(raw_url[0])+1):
name.append('string_%d' % k)
#分割字符串
j=1
for i in range(int(raw_url[0])):
count=0
name[j-1]=[]
position_1=new_url.find(split_char[i])
position_2=new_url.find(split_char[j])
if position_1==position_2:
position_2=new_url.find(split_char[j],position_1+1,max_num)
if position_2-position_1>=max_num-1:
name[j-1].append(new_url[count:position_2])
new_url=new_url.replace(new_url[count:position_2],'')
else:
position_3=new_url.find(split_char[j],position_2+1,max_num)
if position_3-position_1>=max_num-1:
name[j-1].append(new_url[count:position_3])
new_url=new_url.replace(new_url[count:position_3],'')
else:
position_4=new_url.find(split_char[j],position_3+1,max_num)
if position_4-position_1>=max_num-1:
name[j-1].append(new_url[count:position_4])
new_url=new_url.replace(new_url[count:position_4],'')
j+=1
if j==int(raw_url[0])+1:
name[j-2]=[]
name[j-2].append(new_url)
print(name)
#补齐,保证每一个list长度都一样,方便使用zip函数
for i in range(len(name)):
if len(name[i][0]) < max_num:
name[i][0]=name[i][0]+'*'*(max_num-len(name[i][0]))
mix_url=''
for a,b,c,d,e,f,g,h in zip(name[0][0],name[1][0],name[2][0],name[3][0],name[4][0],name[5][0],name[6][0],name[7][0]):
mix_url+=a+b+c+d+e+f+g+h
mix_url=mix_url.replace('*','') #去掉自己添加的‘*’号
mix_url=urllib.parse.unquote(mix_url).replace('^','0') #把'^','0'变为0字符
file_name=mix_url.split('/')[-1].split('?')[0] #mp3文件名
if not os.path.exists('D:\\xiami_music'): #保存音乐的文件夹
os.makedirs('D:\\xiami_music')
os.chdir('D:\\xiami_music')
req=requests.get(mix_url)
with open('D:\\xiami_music\\'+file_name,'wb') as file: #下载文件
file.write(req.content)
print('download ok')
欢迎大家不吝赐教。
上一篇: table 表格,序号控制
下一篇: Musixtex写五线谱