原由:老爸让我下载几千首歌曲给他在车上播放,感受手动下载,就算批量下载也要时间,索性写个爬虫自动下载吧。。html
对于这个爬虫小项目,选择了node+koa2,初始化项目koa2 projectName
(须要先全局安装koa-generator
),而后进入项目文件,npm install && npm start
,其中依赖用到了superagent, cheerio, async, fs, path
node
打开网易云网页版,点击歌单页面,我选择了华语分类,右键查看框架源码,获取真实url,找到id为m-pl-container
的html结构,这就是此次须要爬取的歌单列表,直接用superagent
请求url,只能爬取到第一页的数据,须要async
来并发爬取npm
static getPlayList(){
const pageUrlList = this.getPageUrl();
return new Promise((resolve, reject) => {
asy.mapLimit(pageUrlList, 1, (url, callback) => {
this.requestPlayList(url, callback);
}, (err, result) => {
if(err){
reject(err);
}
resolve(result);
})
})
}
复制代码
其中const asy = require('async')
,由于用到async/await
,因此区分下,requestPlayList
是superagent发起的请求小程序
static requestPlayList(url, callback){
superagent.get(url).set({
'Connection': 'keep-alive'
}).end((err, res) => {
if(err){
console.info(err);
callback(null, null);
return;
}
const $ = cheerio.load(res.text);
let curList = this.getCurPalyList($);
callback(null, curList);
})
}
复制代码
getCurPalyList
是获取页面上的信息,传入$
用于dom操做bash
static getCurPalyList($){
let list = [];
$('#m-pl-container li').each(function(i, elem){
let _this = $(elem);
list.push({
name: _this.find('.dec a').text(),
href: _this.find('.dec a').attr('href'),
number: _this.find('.nb').text()
});
});
return list;
}
复制代码
至此,歌单列表爬取完成,接下来要爬取歌曲列表并发
static async getSongList(){
const urlCollection = await playList.getPlayList();
let urlList = [];
for(let item of urlCollection){
for(let subItem of item){
urlList.push(baseUrl + subItem.href);
}
}
return new Promise((resolve, reject) => {
asy.mapLimit(urlList, 1, (url, callback) => {
this.requestSongList(url, callback);
}, (err, result) => {
if(err){
reject(err);
}
resolve(result);
})
})
}
复制代码
requestSongList
的使用跟上面playList的差很少,所以再也不重复。上面代码获取到歌曲列表后,须要下载到本地框架
static async downloadSongList(){
const songList = await this.getSongList();
let songUrlList = [];
for(let item of songList){
for(let subItem of item){
let id = subItem.url.split('=')[1];
songUrlList.push({
name: subItem.name,
downloadUrl: downloadUrl + '?id=' + id + '.mp3'
});
}
}
if(!fs.existsSync(dirname)){
fs.mkdirSync(dirname);
}
return new Promise((resolve, reject) => {
asy.mapSeries(songUrlList, (item, callback) => {
setTimeout(() => {
this.requestDownload(item, callback);
callback(null, item);
}, 5e3);
}, (err, result) => {
if(err){
reject(err);
}
resolve(result);
})
})
}
复制代码
其中requestDownload
是请求downloadUrl并下载保存到本地dom
static requestDownload(item, callback){
let stream = fs.createWriteStream(path.join(dirname, item.name + '.mp3'));
superagent.get(item.downloadUrl).set({
'Connection': 'keep-alive'
}).pipe(stream).on('error', (err) => {
console.info(err); // error处理,爬取错误时,打印错误并继续向下执行
})
}
复制代码
到此,爬虫小程序完成。该项目爬取歌单列表-->歌曲列表-->下载到本地,固然也能够直接找到某位歌手的主页,修改传入songList的url,直接下载该歌手的热门歌曲。koa