前言刚开始学习node的时候,我用爬虫爬过一些磁力链接。具体可以看shy节点爬虫,但是没有并发,没有代理,当时对异步还不太了解,所以这次又写了一个爬虫来爬bilibili壁纸站的所有壁纸,爬100张happy代理的ip,并将有用的ip保存到json文件中用到的模块async(控制并发)cheerio(解析DOM)superagent(http库)superagent-proxy(使用代理)fs(读写文件)具体cheerio和superagent的用法,看我之前的可耻节点爬虫。但是我之前是初学者,代码写的很丑。代理ip有什么用?我们在访问互联网资源时,都是通过自己的ip(身份证)访问的,爬虫不得不频繁获取互联网资源。因此,如果您在某个时间点频繁访问某个网站的某个资源,对网站服务器造成压力,则可能被网站管理。那些封禁ip,让自己无法访问网站的,代理ip就是伪造身份访问如何查看ip是否可用。这里使用了superagent的一个扩展,superagent-proxy,然后用来访问http://ip.chinaz.com/getip。如果aspx能在3s内返回一个值,证明ip是可以的constsuperagent=require('superagent')require('superagent-proxy')(superagent);//先写你要测试的ip,下面只是为了测试iplettestIp='http://61.178.238.122:63000';(asyncfunction(){superagent.get('http://ip.chinaz.com/getip.aspx').proxy(testIp).timeout(3000).end((err,res)=>{if(res===undefined){console.log('hanged');return}if(err){console.log('报告错误')}console.log('Success:'+res.text)})}())抓取ip并存储首先我们看一下我们要抓取的happyagent的DOM我们要爬取ip地址放在tr标签的第一个td上点击第二个页面,链接就变成了http://www.kxdaili.com/dailiip/1/2上的数组表示.html#iplink必须是页数,也就是说我们只需要改变链接上数字的值就可以得到其他页面的html代码如下:constsuperagent=require('superagent')constcheerio=require('cheerio')constfs=require('fs')constapiFunc=require('../common/apiFunc')//一些封装的读写API//抓取ipconst网站='http://www.kxdaili.com'leturl=website+'/dailiip/1/'//总执行函数letgetIp=asyncfunction(){//promise中存储的数组lettasks=[]//读取存储的ip在ip.js本身让ips=awaitapiFunc。readFile('./ip.js')ips=JSON.parse(ips)for(letpage=1;page<=10;page++){letres=awaitsuperagent.get(url+page+'.html')let$=cheerio.load(res.text)lettr=$('tbody>tr')for(leti=0;i
{//过滤掉返回值为undefined的数据letusefulIp=arr.filter((item)=>{return(item!==undefined)})ips=JSON.stringify(ips.concat(usefulIp))console.log(ips)apiFunc.writeFile('./ip.js',ips)})}getIp()module.exports=getIp爬取bilibili壁纸站。我们先进入bilibili壁纸网站,发现有一个按钮可以点击加载更多。如果对前端有所了解的话,应该知道这是通过ajax请求异步获取数据的,所以我们打开开发者果然,NetWork在XHR栏中找到了一个api,返回一个json文件,里面存放了所有的缩略图当前页面的壁纸信息。仅仅依靠这个json文件,我们就可以爬取所有壁纸的缩略图,但是我们要的是高清大图,所以我们随便点一个缩略图,发现它的url的参数(il_id,width,height)都是我们之前获取的json里面的数据,也就是说我们可以拼接链接得到高清图片的链接,然后用cheerio解析DOM得到图片地址就可以了!!!!!!!!!然而,哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈竭惊想过会够了,又找了一个api,高清图片的url就是api返回的json数据中的il_file。所以我们只需要拼接api链接,然后使用superagent请求获取高清图片的url即可。想想如何获取缩略图api返回包含高清图片数据的json将1的json数据拼接到高清图片的api链接,将所有的api链接存储在一个数组中同时获取2中的apiarray,获取所有图片url,并将url存放在一个数组中并发下载,数组中的图片url存放在本地文件夹中。这样一来,在爬取bilibili壁纸站时,就不需要解析DOM了。也就是说,不需要使用cheerio模块。代码如下:constsuperagent=require('superagent')require('superagent-proxy')(superagent);constfs=require('fs')constcheerio=require('cheerio')constasync=require('async')//获取bilibiliAPI的json数据letjsonUrl='http://h.bilibili.com/wallpaperApi?action=getOptions&page=1'letproxy="http://218.201.98.196:3128"letgetPicJson=function(){returnnewPromise((resolve,reject)=>{superagent.get(jsonUrl).proxy(proxy).end((err,res)=>{if(err)console.log('ProxyError')if(res===undefined)returnif(res.statusCode==200){letjson=JSON.parse(res.text)resolve(json)}})})}//获取high的json数据-定义图片apiletdealHd=asyncfunction(){letpicHd=[]letpicJson=awaitgetPicJson()letpicLength=picJson.lengthfor(leti=1;i{letq=async.queue((hDJson,callback)=>{vardelay=parseInt((Math.random()*30000000)%1000,10);//设置延迟和并发爬取concurrencyCount++;console.log('当前并发数为',concurrencyCount,',currentlyGet',hDJson.title,'delay',delay,'milliseconds');superagent.get(hDJson.url).proxy(proxy).end((err,res)=>{if(err){console.log(呃);回调(空);}else{//let$=cheerio.load(res.text)//lethdUrl=$('#wallpaper').attr('id')//console.log('linkis'+hdUrl)letpic={}pic.title=hDJson.titlepic.url=res.body[0].detail[0].il_filepic.format=pic.url.match(/.{3}$/)[0]//console.log(result)result.push(pic)concurrencyCount--callback(null)}})},5)q.drain=function(){resolve(result)}q.push(hdJson)})}//下载高清图片letdownloadImg=asyncfunction(){console.log('开始下载图片...');//letfolder=`Data/img-${Config.currentImgType}-${Config.startPage}-${Config.endPage}`;//fs.mkdirSync(文件夹);让下载计数=0;var并发数=0;letq=async.queue(function(image,callback){//console.log('正在下载:'+image.title);vardelay=parseInt((Math.random()*30000000)%1000,10);//设置延迟并发爬取并发计数++;console.log('当前并发数为',concurrencyCount,',正在取数为',image.title,'delay',delay,'milliseconds');superagent.get(image.url).proxy(proxy).end(function(err,res){if(err){console.log(err);callback(null);}else{downloadCount++;fs.writeFile(`./picture/${downloadCount}-${image.title}.${image.format}`,res.body,function(err){if(err){console.log(err);}else{console.log("图片下载成功");}setTimeout(()=>{concurrencyCount--;callback(null);},delay)});}});},5);//当所有任务都执行完后,这个函数就会被调用q.drain=function(){console.log('Allimgdownload');}让imgList=awaitdealPicJson();q.push(imgList);//将所有任务加入队列}downloadImg()asynccontrolconcurrency控制并发我一般使用async.maplimit,因为我是第一次接触但是看到一篇介绍async.queue的文章,所以我试过了。不同的是,mapLimit会在队列结束后返回所有并发任务的结果数组,所以没有队列,所以你要自己设置一个变量,用来存放每个并发任务返回的结果。具体api用法见:asynccommonapi运行结果后记下github代码:bilibili壁纸爬虫里面有一些必要的注释。有4个js可以运行./aboutIp/getIp.js(用来抓取有用的代理ip)。可用)app-thumbnails.js(用于爬取壁纸缩略图)app-hd.js(用于爬取壁纸高清图片)虽然了解的很浅,但是你是不是也能渐渐感受到爬虫的魅力呢?