前言很多程序员在刚开始学习开发的时候应该会有一个想自己开发一个爬虫的想法(至少我有)。所以爬虫在国内互联网上也是盛行!学了node.js之后发现比较适合写爬虫,但是一直没有开始写。正好这段时间有空,就写个爬虫玩玩。你在想什么攀登?他们都喜欢看电影,让我们从时光网的国内票房排行榜上爬下来吧。谈话很便宜。给我看代码不bb,怎么把代码“吃”到这里gitclonehttps://github.com/XNAL/node-MovieSpidercdnode-MovieSpidernpminitnodeindex.js搭建环境开发语言:node.jshttp发布request:superagentconcurrencycontrol:asyncwebpage内容分析:cheerio启动代码1.代码主体是一个简单的例子,本次不会开启node服务。我这里直接使用自执行的方式。如果需要,可以根据自己的需要进行扩展。//启动时直接执行代码(functionspider(){util.fetch_data_get(reqUrl,reqParams).then((result)=>{//根据页面结构获取页面总数,然后获取数据在页面中让$=cheerio.load(result.body.html);让pageTotal=$('.bocontent.pagesizea:last-child').data('page')||0;console.log('Totalpagesofmoviedata:',pageTotal);returnpageTotal;}).then((pageTotal)=>{//分页获取数据getMovieData(0,pageTotal);}).catch((err)=>{console.log('获取链接失败:',err);})})();2.发送请求因为代码需要多次发送http请求,所以最好把http请求写成public方法。使用上面提到的superagent库来实现。//公共方法:通过get请求获取数据functionfetch_data_get(url,queryParams){returnnewPromise((reslove,reject)=>{superagent.get(url).set(setting.header).query(queryParams).end((err,result)=>{err?reject(err):reslove(result);})})}3.根据手动操作分析目标网站的apihttp://movie.mtime.com/boxoffice/?year=2017&area=china&type=MovieRankingYear&category=all&page=0&display=list×tamp=1505818638620&version=07bb781100018dd58eafc3b35d42686804c6df8d&dataType=json可以得到如下参数:/';constreqParams={'year':2017,'area':'china','type':'MovieRankingYear','category':'all','page':0,'display':'list','timestamp':1501576013654,'版本':'07bb781100018dd58eafc3b35d42686804c6df8d','dataType':'json'};因为这次我们要获取2017年内地票房排行榜。通过分析可以看出,主要需要改变的是page参数,所以这里需要根据页面返回的内容获取总页数。4.使用cheerio获取需要的参数。可以查看api返回的页面内容:将api获取的数据格式化后的页面代码。这里需要使用cheerio来获取总页数。Cheerio可以理解为服务端的jQuery,用法类似://根据页面结构获取总页数,然后分页获取数据let$=cheerio.load(result.body.html);letpageTotal=$('.bocontent.pagesizea:last-child').data('page')||0;5。开始分页获取目标数据<1>调用上面提到的public方法fetch_data_get获取数据,进而获取页面内容。图片地址先保存在movieImgs中,最后统一下载图片://根据页面结构获取需要的数据let$=cheerio.load(result.body.html);$('.bocontent.boxofficelistdd').each((idx,elem)=>{$(elem).find('div.movi??etopmod').each((i,el)=>{让_this=$(el);让arrLeadActor=[];_this.find('.txtboxbp').eq(1).find('a').each((idx,ela)=>{arrLeadActor.push($(ela).text());})movieData.push({rank:_this.find('.picboxi').text(),img:_this.find('.picboximg').attr('src').replace(/\/u\//,""),名称:_this.find('.txtboxh3').text(),导演:_this.find('.txtboxbp').eq(0).find('a')。text(),leadActor:arrLeadActor.join(','),点:_this.find('.gradebox.point').text(),总计:_this.find('.totalbox.totalnum').text()}),movieImgs.push(_this.find('.picboximg').attr('src').replace(/\/u\//,""));})})<2>根据页码循环数据if(pageIndex<=pageTotal){//设置超时防止网站反爬虫setTimeout(()=>{pageIndex++;getMovieData(pageIndex,pageTotal);},setting.timeout);}<3>数据全部取出后,存储数据,下载图片。因为只是一个简单的例子,所以这次只是将数据保存到json文件中。如果需要对数据进行后续操作,最好保存在数据库中:fs.writeFile(dataDir+reqParams.year+'.json',JSON.stringify(movieData),(err)=>{if(err){console.log(err);}else{console.log('数据写入成功');}});调用下载图片的方法:letfolderName=imgPrefix+reqParams.year;util.downloadImg(movieImgs,folderName);util.js中的downloadImg方法:这里需要用到上面提到的async,用于并发控制,否则很短的时间内至少发送几十上百个请求。网站的爬虫程序被屏蔽,大量的并发也会导致出错的概率较高。//异步下载图片path.basename(img);letfolder=imgDir+folderName;if(!fs.existsSync(folder)){fs.mkdirSync(folder);}fs.writeFile(folder+'/'+fileName,result.body,(err)=>{if(err){console.log(img,'写入图片失败:',err);}else{console.log(img,'写入图片成功');callback(null,fileName);}})}).catch((err)=>console.log(err))},(err,result)=>{if(err){console.log('图片下载失败:',err)}else{console.log(result);}})}结论至此,一个简单的node.js版本的爬虫已经开发完成。其实在了解了爬虫的原理之后,回过头来发现开发一个简单的爬虫是非常容易的。最后欢迎大家到我的github上star和fork。
