最近一直在学英语,所以写了个爬虫爬取歌单并下载,而后随时均可以听。 GitHub地址:https://github.com/leeseean/nodejs-crawler。
要用爬虫下载音频,那天然是要找到音频连接了。而网站的音频连接没有直接暴露出来,所以须要分析找出获取音频连接的办法。 进入喜马拉雅官网主页,随便找一个主播的页面进入,我这里找的是[英语主播Emily](http://www.ximalaya.com/29101549/album/2801092)的主页,而后里面有她的播单,F12打开一看这些歌单都没有直接写音频连接。可是仍是有一些规律的,每一个音频都有一个ID,后面点击这个音频的时候,会有一个AJAX请求,请求的连接就包含这个ID,这个请求会返回音频的真实连接,这样就拿到了音频连接。如图
点击音频发出AJAX请求,请求返回数据里面包含真实音频连接,如图
需求分析完了,那如今固然是写爬虫了,首先爬取主播页,拿到ID,而后根据ID发送AJAX请求拿到真实音频地址。 用的模块有cheerio和request。
const request = require('request'); const fs = require('fs'); const cheerio = require('cheerio'); //这个时间后面设置cookie须要用到 const formatTime = (new Date()).toLocaleString().replace(/\//g, '-').replace(/[\u4E00-\u9FA5]/g, '');
直接用request(url,callcack)发现返回一个301重定向的页面,所以要设置uset-agent和cookie才能正确访问到页面。如图,
相应设置代码以下:html
function setOptions({ url, cookies, contentType }) { const jar = request.jar(); jar.setCookie(request.cookie(cookies), url); return { url: url, jar: jar, method: 'GET', headers: { "Connection": "keep-alive", "Content-Type": contentType, "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36" } }; }
请求到页面到拿到全部音频的ID,并根据音频ID发送AJAX请求,代码以下:
function getListIdsCallback(error, response, body) { if (!error && response.statusCode === 200) { const listIds = [];//存放全部音频ID的数组 const $ = cheerio.load(body); $('div.album_soundlist > ul > li > div > a.title').each((index, item) => { listIds.push($(item).attr('href').split('/')[3]); }); getAudioJson(listIds);//获取音频真实连接并下载音频 } }
代码以下:
function getAudioJson(listIds) { if (listIds.length === 0) { return; } const id = listIds.shift(); request(setOptions({ url: `http://www.ximalaya.com/tracks/${id}.json`, cookies: `_xmLog=xm_1510364052559_j9unrdjjmwt7gx; login_from=qq; nickname=All2005; login_type=QQ; 1&remember_me=y; 1&_token=96575028&ecb632710362104767080ce01362b33cc881; trackType=web; x_xmly_traffic=utm_source%3A%26utm_medium%3A%26utm_campaign%3A%26utm_content%3A%26utm_term%3A%26utm_from%3A; Hm_lvt_4a7d8ec50cfd6af753c4f8aee3425070=1510364053; Hm_lpvt_4a7d8ec50cfd6af753c4f8aee3425070=1510376453; _ga=GA1.2.1519968795.1510364053; _gat=1; 1_l_flag=96575028&ecb632710362104767080ce01362b33cc881_${formatTime}; msgwarn=%7B%22category%22%3A%22%22%2C%22newMessage%22%3A0%2C%22newNotice%22%3A0%2C%22newComment%22%3A0%2C%22newQuan%22%3A0%2C%22newFollower%22%3A0%2C%22newLikes%22%3A0%7D`, contentType: 'text/html;charset=utf-8', }), (error, response, body) => { return getAudioJsonCallback(error, response, body, listIds); }); } function getAudioJsonCallback(error, response, body, listIds) { if (!error && response.statusCode === 200) { const JsonData = JSON.parse(body); downloadFile(JsonData['play_path'], `${JsonData['id']}.m4a`, (e) => { console.log(`下载完毕${JsonData['id']}`); getAudioJson(listIds); }); } } function downloadFile(url, filename, callback) { const stream = fs.createWriteStream(filename); request(url).pipe(stream).on('close', callback); }
这里获取到listIds一开始是使用一个循环去下载,后面发现一会儿同时开启几十个下载node根本吃不消,下下来的音频不完整,后面采用一个一个下载的办法,就彻底解决的这个问题。相关代码以下:
const id = listIds.shift();//每次取出一个id去请求 downloadFile(JsonData['play_path'], `${JsonData['id']}.m4a`, (e) => { console.log(`下载完毕${JsonData['id']}`); getAudioJson(listIds);//下载完后再次启动请求 });
先写到这了。爬虫的关键就是找出真实地址,而后抓页面的时候若是抓不到记得补充cookie,设置user-agent等一类参数。