Python抓取百度音乐

你在百度去搜索一首歌时,你会发现有种更简单的方法,嘿嘿,安宁ヤ太天真告诉你个秘密,百度有个不公开的API 

这次这个真的是干货哦,昨晚弄了半晚上,,,,从8点吃完饭就开始写,一直到了快12点才弄好,,,新手,伤不起呀。。。。
先简单的说下吧,百度提供了一个音乐搜索的api,你想百度请求类似于

澳门新葡萄京官网首页 1
Title:Python抓取百度音乐

 
用上面的地址,红色部分改成歌名与作者名,然后百度就会给你一个XML: 

Author:Insun

Java代码  澳门新葡萄京官网首页 2

的地址,百度会给你返回一段xml,如下所示

Content:

  1. <?xml version=”1.0″ encoding=”gb2312″ ?>   
  2. <result>  
  3.    <count>1</count>   
  4. <data>  
  5. <encode>;   
  6. <decode>1.Wma</decode>   
  7. <type>2</type>   
  8. <lrcid>49684</lrcid>   
  9.     </data>  
  10. </result>  

 代码如下

可以根据歌手名称来搜他的音乐 

其中的count值为1是说返回的是一个,这个没什么用,接下来的东西就有用了,encode里的值是歌曲加密后的地址,加密只是对文件名加密的,我们需要的只是前面的路径,也就是
这部分,然后复制decode
的值: 1.Wma 与前面的相拼就是正确的下载地址: 
 
后面的type的值为2表示此歌曲文件类型是wma的,其它的:1表示rm,0表示MP3,通常我们下的类型都是MP3或WMA的,所以只要有2或0的 
lrcid这个的值是百度服务器上这首歌的歌词文件的文件名,这个文件的路径是:  

This XML file does not appear to have any style information associated
with it. The document tree is shown below.
<result>
<count>1</count>
<url>
<encode>
<![CDATA[
 

 
]]>
</encode>
<decode>
<![CDATA[
12762845.mp3?xcode=e6b69cf593ea22ac9d2b9314e565fc0caf85125f065ce3e0&mid=0.31929107437537
]]>
</decode>
<type>8</type>
<lrcid>2829</lrcid>
<flag>1</flag>
</url>
<durl>
<encode>
<![CDATA[
 

 
]]>
</encode>
<decode>
<![CDATA[
7345405.mp3?xcode=e6b69cf593ea22ac78e1478e78479dc19e8e4650995cb99a&mid=0.31929107437537
]]>
</decode>
<type>8</type>
<lrcid>2829</lrcid>
<flag>1</flag>
</durl>
<p2p>
<hash>f98b6772aa97966550ec80617879becee0233bf4</hash>
<url>
<![CDATA[ ]]>
</url>
<type>mp3</type>
<size>3778335</size>
<bitrate>128</bitrate>
</p2p>
</result>

譬如搜陈奕迅 有1161首歌曲 

这个地址解析下: 

这个是百度lrc歌词存放地址,后面的496是一个的不定的,民就是说歌曲不同那个目录名也不同,它的算法是拿歌词文件名(也就是上面说的
49684) 除以一百,然后取小于等于其结果的最大整数,如上面的:49684/100
=496.84 取小于等于496.84
的最大整数就是496,于是这首歌完整的歌词地址就出来了: 

简单的说明下,由于我们要做的只是获取到歌曲的lrc歌词地址,所以有用的只有2829这个标签。
澳门新葡萄京官网首页,而encode和decode里面的拼接起来就是mp3的下载地址,如本例的

 urlencode。

安宁ヤ太天真似乎说得复杂了了,呵呵,希望对大家有用 

正则匹配一个页面上所有的歌名,一个分页20个。(这里就没去抓其他分页了)

Java代码  澳门新葡萄京官网首页 3

就是下载地址,不过音质太差,有时间在研究下这个。
继续说歌词,注意lrcid标签里面的2829
这个是百度lrc歌词存放地址,
然后本例的歌词地址是
看到了吧,歌词地址后面的两个数字的计算方法是在lrcid除以100所获得的整数,就是第一个数字,然后第二个数字就是lrcid,然后后面加上后缀.lrc就搞定了
获得lrc地址之后就简单了,只要请求该地址,然后将获取到的内容写入文件就ok了。
好了,大概就是这样,下面是代码

然后根据一个百度音乐老接口API ,现在的音乐盒域名是play.baidu.com

  1. <appSettings>    
  2.   <!–搜搜音乐地址 ;    
  3.   <!–格式: -1-全部 0-MP3 1-RM ,2-WMA–>    
  4.   <add key=”SosoUrl” value=”;    
  5.   <!–百度音乐地址 ;    
  6.   <!—格式:-1-全部 0-MP3 1-RM ,2-WMA–>    
  7.   <add key=”BaiduUrl” value=”;    
  8.   <!–百度音乐快搜地址 ;    
  9.   <add key=”BaiduQuickUrl” value=”;    
  10.   <!–千千静听歌词信息地址 ;    
  11.   <add key=”TTLrcListUrl” value=”;    
  12.   <!–千千静听歌词地址 ;    
  13.   <add key=”TTLrcUrl” value=”;    
  14. </appSettings>    

 代码如下

原文地址:

import os
import os.path
import re
import eyed3
import urllib2
import urllib
from urllib import urlencode
import sys
 
import os
reload(sys)
sys.setdefaultencoding(‘utf8’)
 
music_path = r”E:\music”
lrc_path = r”e:\lrc”
 
os.remove(‘nolrc.txt’)
os.remove(‘lrcxml.txt’)
 
the_file = open(‘lrcxml.txt’,’a’)
nolrc_file = open(‘nolrc.txt’,’a’)
 
for root,dirs,files in os.walk(music_path):
    for filepath in files:
        the_path = os.path.join(root,filepath)
        if (the_path.find(“mp3”) != -1):
            print the_path
            the_music = eyed3.load(the_path)
            the_teg = the_music.tag._getAlbum()
            the_artist = the_music.tag._getArtist()
            the_title = the_music.tag._getTitle()
           # print the_teg
           # print the_title
           # print the_artist
            b = the_title.replace(‘ ‘,’+’)
           # print b
            a = the_artist.replace(‘ ‘,’+’)
            #print urlencode(str(b))
            if isinstance(a,unicode):
                a = a.encode(‘utf8’)
            song_url =


         
            the_file.write(song_url+’\n’)
            page = urllib2.urlopen(song_url).read()
            print page
            theid = 0
            
            lrcid = 
re.compile(‘<lrcid>(.*?)</lrcid>’,re.S).findall(page)
            have_lrc = True
            if lrcid != []:
                theid = lrcid[0]
                
            else:
                nolrc_file.write(the_title+’\n’)
                have_lrc = False
            print theid
            
            
            if have_lrc:
                firstid = int(theid)/100
                lrcurl =
“”
                print lrcurl
                lrc = urllib2.urlopen(lrcurl).read()
                if(lrc.find(‘html’)== -1):
                    lrcfile =
open(lrc_path+”\\”+the_title+”.lrc”,’w’)
                    lrcfile.writelines(lrc)
                    lrcfile.close()
                else:
                    nolrc_file.write(the_title+’\n’)
                
the_file.close()
nolrc_file.close()
print “end!”

<count>5</count>

有用第一步请求所获取到底是xml格式的,所以本来想着解析xml来获取lrcid,但是在实现过程中遇到了各种问题,别的还容易,就在这一块儿浪费的时间最长,纠结未果之后,只能改用正则表达式来获取了。。。只能说明还是学艺不精呢,

<url>

<encode>

/ZGVsZ2tsamxfn6NndK6ap5WXcGeba5lsZ2qXmGlunZ1ilmqVmGuammFjlWxsamtrYmeWWqKfm3VhYGhqamxsaWFlZ2RtanBuMQ$$

</encode>

<decode>33936634.mp3?xcode=3f5b468dd48fe1d7ac5cb01b8744315c&mid=0.56565103408496

</decode>

<type>8</type>

<lrcid>2399</lrcid>

<flag>1</flag>

</url>

 

XML文件 count是说有5个可以下载的资源

我们直接取第一个

encode加密的链接是

 

/ZGVsZ2tsamxfn6NndK6ap5WXcGeba5lsZ2qXmGlunZ1ilmqVmGuammFjlWxsamtrYmeWWqKfm3VhYGhqamxsaWFlZ2RtanBuMQ$$

 

红色部分就是下面decode的内容

<decode>33936634.mp3?xcode=3f5b468dd48fe1d7ac5cb01b8744315c&mid=0.56565103408496

 

</decode>

 

我们python字符串处理一下 根据最后一个“/”来截取 最后拼凑成

33936634.mp3?xcode=3f5b468dd48fe1d7ac5cb01b8744315c&mid=0.56565103408496

 

<?xml version=”1.0″ encoding=”gb2312″ ?>

<result><count>5</count><url>

<encode>

<![CDATA[

ZGVsZ2tsamxfn6NndK6ap5WXcGeba5lsZ2qXmGlunZ1ilmqVmGuammFjlWxsamtrYmeWWqKfm3VhYGhqamxsaWFlZ2RtanBuMQ$$]]>

</encode>

<decode>

<![CDATA[33936634.mp3?xcode=3f5b468dd48fe1d7ac5cb01b8744315c&mid=0.56565103408496]]>

</decode><type>8</type><lrcid>2399</lrcid><flag>1</flag></url>

<durl>

<encode>

<![CDATA[

YmpjZmpmbmaeomZzrZmmnJZvZppqmGtuaZaXaG2cnGmVaZSXapmZaGKUa2tpamppZpVZoZ6adGhfZ2lpa2toaGRmY2xpb204]]>

</encode><decode><![CDATA[1802507.mp3?xcode=3f5b468dd48fe1d7ac5cb01b8744315c&mid=0.56565103408496]]>

</decode><type>8</type><lrcid>2399</lrcid><flag>1</flag></durl>

澳门新葡萄京官网首页 4

 

 源代码里是有CDATA的 所有正则时候要处理一下

type是类型 是mp3呢还是wma呢还是rm呢。。等等。。

lrcid 是个取整的算法 除以一百,然后取小于等于其结果的最大整数  2399/100 =
23

然后分songs和lrcs目录下载下来

#!/usr/bin/env python

#! -*- encoding:utf-8 -*-

”’

根据歌手去找歌曲 一页20首歌 

然后根据歌名和歌手来下载歌曲和歌词

20首歌和歌词 接近1M/s的网速 花了33.9479383463s

author:insun

”’

import urllib,re,sys,os,time

reload(sys)

sys.setdefaultencoding(‘utf-8’)

 

def musicScapy(singername):

    query =  urllib.quote(singername)

    url = ‘

    response = urllib.urlopen(url)

    text = response.read()

    #<span class=”song-title”  style=”width: 170px;” ><a
href=”/song/7316463″ class=”” data-songdata='{ “id”: “” }’
title=”爱情转移”>爱情转移</a>

    reg = re.compile(r'<span
class=”song-title”.+?>.+?<a.+?>(.*?)</a>’,re.S)

    groups = re.findall(reg,text)

    ”’判断目录songs和lrcs是否存在,不存在创建。否则报错”’

    if (os.path.exists(‘songs’)== False):

        os.mkdir(‘songs’)

    if(os.path.exists(‘lrcs’) == False):

        os.mkdir(‘lrcs’)

 

    for musicname in groups:

        try:

            xml =
 urllib.urlopen(”

                   + musicname+’$$’+singername +’$$’).read()  

            encode =
 re.compile(‘<encode>.*?CDATA[(.*?)]].*?</encode>’,re.S).findall(xml)[0]
 

            decode =
 re.compile(‘<decode>.*?CDATA[(.*?)]].*?</decode>’,re.S).findall(xml)[0]
 

            lrcid =
 re.compile(‘<lrcid>(.*?)</lrcid>’,re.S).findall(xml)[0]

            #encode.rindex(‘/’) 最后出现’/’的位置

            

            musicname = musicname.decode(‘utf-8’)

            musiclink = encode[:encode.rindex(‘/’)+1] + decode

            lrclink =

            #song download

            urllib.urlretrieve(musiclink,’songs/’+ musicname+’.mp3′)

            #lrc download

            urllib.urlretrieve(lrclink,’lrcs/’+ musicname+’.lrc’)

        

        except BaseException:

            print ‘download failed’

            continue  

            

if __name__ == ‘__main__’:

    beginTime = time.clock()

    musicScapy(‘陈奕迅’)

    endTime = time.clock()

    print endTime-beginTime

 

 

 

用gevent的话花了37.5646471024s 肯定大批量数据 gevent比较给力吧

 

Author:Insun Content:
可以根据歌手名称来搜他的音乐 譬如搜陈奕迅 有1161首歌曲

发表评论

电子邮件地址不会被公开。 必填项已用*标注