关于
落网,一个高逼格的音乐网站,是很多文艺青年经常逛的网站。经常下载落网音乐到本地,一首一首的下载十分的痛苦。最近刚好在学习python爬虫的东西,刚好把落网音乐的爬取当做一个练习项目来实践(IT从业者的好处~)。
准备
工具 :python 2.7,PyCharm
类库:urllib2、BeautifulSoup、time、re、sys
分析
要想下载落网的音乐,首先要获取每首音乐的url,通过chrome浏览器的开发者工具(F12)查看网页的源代码可以看到图片的URL,没有音频的URL,如图
但是,我们发现点击每首歌曲的时候,network都会一个音频的请求,如图
那么很显然,这个就是我们需要的下载URL地址了。通过分析http://mp3-cdn2.luoo.net/low/luoo/radio924/02.mp3这个地址,我可以知道前面部分http://mp3-cdn2.luoo.net/low/luoo/是固定的地址,后面的radio924/02.mp3中924是每个期刊的期刊号,其中02是每个期刊下面的第几首歌。要想获取同类型期刊(比如rock),URL为http://www.luoo.net/music/rock,首先我们要获取每个期刊的期刊号于期刊URL的对应关系,通过抓取HTML源码来获得,如图
代码如下:
#获取每个期刊URL与频道的对应关系,存放在一个dict中
def getReation(self, pageIndex):
soup = self.getPage(pageIndex, '')
vols = {}
pattern = re.compile('[0-9]+') //正则匹配获取HTML源码中的期刊号
if not soup:
return None
vol_lists = soup.find_all('div', class_='meta')
for vol in vol_lists:
vol1 = re.search(pattern, str(vol.a.get_text())).group()
vols[vol1.strip()] = vol.a['href']
return vols
然后根据上面的对应关心来获取每首歌的信息,同样存放在一个dict中,以songName为key,以URL为value,如下。
#获取每首歌的名称和url
def getSongInfo(self, vols):
songInfos = {}
for vol in vols.keys():
url = vols[vol]
soup = self.getPage(0, url)
total = len(soup.find_all('li', class_='track-item'))
songNames = soup.find_all('a', class_='trackname')
for i in range(1, total+1):
songName = self.delSongName(songNames[i - 1].get_text())
if i < 10: //对前面【1-9】首的URL进行格式化。
songURL = self.music_url + 'radio' + str(vol).lstrip('0') + '/0' + str(i) + '.mp3'
else:
songURL = self.music_url + 'radio' + str(vol).lstrip('0') + '/' + str(i) + '.mp3'
songInfos[songName] = songURL
return songInfos
获取到每首歌的信息后,然后我们就可以正式的进行下载了(哈哈,终于到正题了~),如下
def downloadSong(self):
totalPage = self.getTotalPage() //首先获取该类型期刊的总的页数
for pageIndex in range(1, int(totalPage)+1):
vols = self.getReation(pageIndex) //获取每一页的期刊号与URL的对应关系
songInfos = self.getSongInfo(vols) //获取歌曲信息name和URL
for songName, songURL in songInfos.items():
time.sleep(5)
print('%s 正在下载中。。。' %(songName))
try:
data = urllib2.urlopen(songURL).read()
except urllib2.URLError:
print("######链接不存在,继续下载下一首########")
with open (('D:\\test\\song\\%s.mp3' %(songName)).decode('utf-8'), 'wb') as f:
f.write(data)
总结
到这边,基本上,对爬取每个类期刊下面的歌曲有了一个整体的思路,大家可以根据这些来实现自己的爬虫额。
下面给出本人的实现代码,给大家一个参考。
#!-*- coding: utf-8 -*-
import urllib2,urllib
from bs4 import BeautifulSoup
import re
import time
import sys
reload(sys)
sys.setdefaultencoding( "utf-8" )
class DownloadSong(object):
def __init__(self,base_url):
self.url = base_url
self.music_url = 'http://mp3-cdn2.luoo.net/low/luoo/'
self.pageIndex = 1
self.headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36'
}
#获取页面的源码
def getPage(self, index, vol_url):
if index != 0:
url = self.url + '?p=' + str(index)
else:
url = vol_url
try:
request = urllib2.Request(url, headers=self.headers)
response = urllib2.urlopen(request).read()
soup = BeautifulSoup(response, 'html.parser')
return soup
except urllib2.URLError, e:
if hasattr(e, 'reason'):
print(u'链接失败,失败原因', e.reason)
return None
#获取总页面数
def getTotalPage(self):
soup = self.getPage(self.pageIndex, '')
if not soup:
return None
totalPage = soup.find_all('a', class_='page')[-1].get_text().strip()
return totalPage
#处理歌曲的名称
def delSongName(self, songName):
return songName.split('.')[1].lstrip().encode('utf-8')
#获取每个期刊URL与频道的对应关系
def getReation(self, pageIndex):
soup = self.getPage(pageIndex, '')
vols = {}
pattern = re.compile('[0-9]+')
if not soup:
return None
vol_lists = soup.find_all('div', class_='meta')
for vol in vol_lists:
vol1 = re.search(pattern, str(vol.a.get_text())).group()
vols[vol1.strip()] = vol.a['href']
return vols
#获取每首歌的名称和url
def getSongInfo(self, vols):
songInfos = {}
for vol in vols.keys():
url = vols[vol]
soup = self.getPage(0, url)
total = len(soup.find_all('li', class_='track-item'))
songNames = soup.find_all('a', class_='trackname')
for i in range(1, total+1):
songName = self.delSongName(songNames[i - 1].get_text())
if i < 10:
songURL = self.music_url + 'radio' + str(vol).lstrip('0') + '/0' + str(i) + '.mp3'
else:
songURL = self.music_url + 'radio' + str(vol).lstrip('0') + '/' + str(i) + '.mp3'
songInfos[songName] = songURL
return songInfos
#下载歌曲
def downloadSong(self):
totalPage = self.getTotalPage()
for pageIndex in range(1, int(totalPage)+1):
vols = self.getReation(pageIndex)
songInfos = self.getSongInfo(vols)
for songName, songURL in songInfos.items():
time.sleep(5) //适当的减慢下载速度,不要给人家服务器造成压力。
print('%s 正在下载中。。。' %(songName))
try:
data = urllib2.urlopen(songURL).read()
except urllib2.URLError:
print("######链接不存在,继续下载下一首########")
with open (('D:\\test\\song\\%s.mp3' %(songName)).decode('utf-8'), 'wb') as f:
f.write(data)
if __name__ == '__main__':
url = 'http://www.luoo.net/music/classical' //传入古典期刊的url
downloadsong = DownloadSong(url) //生成一个对象
downloadsong.downloadSong() //调用downloadSong方法来正式下载额。
结果如下
如果对您有点帮助的话,麻烦您给点个赞,谢谢。
scrapy版本的Python + Scrapy爬取高逼格音乐网站《落网》