最近在学英语,所以写了一个爬虫来爬取下载歌单,然后就可以随时收听了。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。constrequest=require('请求');constfs=require('fs');constcheerio=require('cheerio');//在这个时间之后设置cookie需要constformatTime=(newDate())。toLocaleString().replace(/\//g,'-').replace(/[\u4E00-\u9FA5]/g,'');直接使用request(url,callcack)找到一个301重定向的页面,所以需要设置uset-agent和cookie才能正确访问页面。如图,对应的设置代码如下:functionsetOptions({url,cookies,contentType}){constjar=request.jar();jar.setCookie(request.cookie(cookies),url);返回{url:url,jar:jar,method:'GET',headers:{"Connection":"keep-alive","Content-Type":contentType,"User-Agent":"Mozilla/5.0(WindowsNT10.0;Win64;x64)AppleWebKit/537.36(KHTML,likeGecko)Chrome/61.0.3163.100Safari/537.36"}};}请求页面获取所有音频ID,根据音频ID发送AJAX请求,代码如下:functiongetListIdsCallback(error,response,body){if(!error&&response.statusCode===200){constlistIds=[];//所有音频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);//获取真实音频链接并下载音频}}获取真实音频链接并下载音频代码如下:functiongetAudioJson(listIds){如果(listIds.length===0){返回;}constid=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%22%Com%2ment3A0%2C%22newQuan%22%3A0%2C%22newFollower%22%3A0%2C%22newLikes%22%3A0%7D`,contentType:'text/html;charset=utf-8',}),(error,response,身体)=>{returngetAudioJsonCallback(error,response,body,listIds);});}functiongetAudioJsonCallback(error,response,body,listIds){if(!error&&response.statusCode===200){constJsonData=JSON.解析(正文);downloadFile(JsonData['play_path'],`${JsonData['id']}.m4a`,(e)=>{console.log(`下载完成${JsonData['id']}`);getAudioJson(列表ID);});}}functiondownloadFile(url,filename,callback){conststream=fs.createWriteStream(filename);request(url).pipe(stream).on('close',callback);}代码技巧这里获取的listId一开始是使用循环下载的,后来发现同时打开了几十个下载节点简直太多了,而且下载的音频不完整。后来用一个一个下载的方法彻底解决了这个问题相关的代码如下:constid=listIds.shift();//每次取出一个id请求downloadFile(JsonData['play_path'],`${JsonData['id']}.m4a`,(e)=>{console.log(`下载完成${JsonData['id']}`);getAudioJson(listIds);//重新开始请求下载后});总结先写到这里。爬虫的关键是找到真实地址,如果在爬取页面时找不到,记得添加cookies,设置user-agent等参数。
