欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

爬取虾米音乐

程序员文章站 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访问以下网页:

  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. 爬取虾米音乐
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')




            
            
    


欢迎大家不吝赐教。