爬取虾米音乐

在网页版的虾米音乐播放器,如何下载音乐。

本次爬虫使用的语言是python3,模块是requests。笔者只是简单的示例,程序中还有许多需要改进的地方。

1、虾米音乐的播放器地址:http://www.xiami.com/play?ids=/song/playlist/id/1774747126#loaded

2、浏览器(笔者使用的是360极速浏览器),右键——审查元素,打开开发者工具。进入network中的XHR,网页歌曲信息是动态加载的。记得要重新刷新网页,才会出现左侧的文件。找到如下图的文件。这个不是标准的json文件。把Response中的代码,复制出来,进行观察,会发现把json378()去掉之后,就是一个标准的json文件。笔者没有用代码处理这一步。



3、具体思路是:大家可以用requests访问以下网页:

  1. Request URL:
    http://www.xiami.com/song/playlist-default/cat/json?_ksTS=1511418676536_377&callback=jsonp378
  2. 然后req.text,再使用strip()函数去掉json378()。就可以得到json文件。再使用json.loads() 提取出location。大家可以使用在线json解析工具,先查找一下。
  3. 音乐的具体网址是隐藏在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')




            
            
    


欢迎大家不吝赐教。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值