当前位置:首页 > Web开发 > 正文

like Gecko) Chrome/59.0.3071.115 Safari/537.36‘}};request(o

2024-03-31 Web开发

本爬虫将从网站爬取排名前几的网站,具体前几名可以具体设置,并分袂爬取他们的主页,查抄是否引用特定库。

github地点

所用到的node主要模块

express 不用多说

request http模块

cheerio 运行在处事器真个jQuery

node-inspector node调试模块

node-dev 改削文件后自动重启app

关于调试Node

在任意一个文件夹,执行node-inspector,通过打开特定页面,在页面长进行调试,然后运行app,使用node-dev app.js来自动重启应用。

所碰到的问题 1. request请求多个页面

由于请求是异步执行的,和分袂返回3个页面的数据,这里只爬取了50个网站,一个页面有20个,所以有3页,通过循环里套request请求,,来实现。

通过添加请求头可以实现根基的反爬虫

措置惩罚惩罚数据的要领都写在analyData()里面,造成后面的数据反复存储了,想了很久,才想到一个解决要领,后面会写到是怎么解决的。

for (var i = 1; i < len+1; i++) { (function(i){ var options = { url: ‘‘ + i, headers: { ‘User-Agent‘: ‘Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36‘ } }; request(options, function (err, response, body) { analyData(body,rank); }) })(i) } 2. 多层回调

仔细不雅察看代码,你会发明,措置惩罚惩罚数据的要领使用了如下的多层回调,也可以不使用回调,写在一个函数内部;因为,每层都要使用上一层的数据,造成了这样的写法。

function f1(data1){ f2(data1); } function f2(data2){ f3(data2); } function f3(data3){ f4(data4); } 3. 正则获取JS库

由于获取页面库,首先需要获取到script的src属性,然后通过正则来实现字符串匹配。

<script src="http://www.mamicode.com/https:/ss0.bdstatic.com/5aV1bjqh_Q23odCf/static/superman/js/lib/jquery-1.10.2_d88366fd.js"></script>

获取到的script可能是上面这样的,由于库名的定名真是各类百般,后来想了一下,因为文件名是用.js结尾的,所以就以点号为结尾,然后把点号之前的字符截取下来,这样获得了库名,代码如下。

var reg = /[^\/\\]+$/g; var libName = jsLink.match(reg).join(‘‘); var libFilter = libName.slice(0,libName.indexOf(‘.‘)); 4.cheerio模块获取JS引用链接

这部分也花了一点时间,才搞定,cheerio获取DOM的要领和jQuery是一样的,需要对返回的DOM东西进行检察,就可以看到东西里隐藏好深的href属性,要领大同小异,你也可以使用其他选择器,选择到script标签

var $ = cheerio.load(body); var scriptFile = $(‘script‘).toArray(); scriptFile.forEach(function(item,index){ if (item.attribs.src != null) { obtainLibName(item.attribs.src,index); } 5.存储数据到数据库

存储数据的逻辑是先获取所有的script信息,然后push到一个缓存数组,由于push后面,紧随着存储到数据库的要领,这两个要领都写在循环里面的,例如爬取5个网站,每个网站存储一次,后面也会随着存储,造成数据反复存储。解决要领是存储数据的一般逻辑是先查,再存,这个查对照重要,盘问的要领也有多种,这里主要是按照库名来查找独一的数据东西,使用findOne要领。注意,由于node.js是异步执行的,这里的闭包,每次只传一个i值进去,执行存储的操纵。

// 将缓存数据存储到数据库 function store2db(libObj){ console.log(libObj); for (var i = 0; i < libObj.length; i++) { (function(i){ var jsLib = new JsLib({ name: libObj[i].lib, libsNum: libObj[i].num }); JsLib.findOne({‘name‘: libObj[i].lib},function(err,libDoc){ if(err) console.log(err); // console.log(libDoc) if (!libDoc){ jsLib.save(function(err,result){ if(err) console.log(‘生存数据堕落‘ + err); }); } }) })(i) } console.log(‘一共存储‘ + libObj.length + ‘条数据到数据库‘); } 6.分页插件

本爬虫前端使用了bootstrap.paginator插件,主要是前台分页,返回数据,按照点击的页数,来显示对应的数据,后期考虑使用AJAX请求的方法来实现翻页的效果,这里的注意项,主要是最后一页的显示,最好前面做个判断,因为返回的数据,不必然恰好是页数的整数倍

function _paging(libObj) { var ele = $(‘#page‘); var pages = Math.ceil(libObj.length/20); console.log(‘总页数‘ + pages); ele.bootstrapPaginator({ currentPage: 1, totalPages: pages, size:"normal", bootstrapMajorVersion: 3, alignment:"left", numberOfPages:pages, itemTexts: function (type, page, current) { switch (type) { case "first": return "首页"; case "prev": return "上一页"; case "next": return "下一页"; case "last": return "末页"; case "page": return page; } }, onPageClicked: function(event, originalEvent, type, page){ // console.log(‘当前选中第:‘ + page + ‘页‘); var pHtml = ‘‘; var endPage; var startPage = (page-1) * 20; if (page < pages) { endPage = page * 20; }else{ endPage = libObj.length; } for (var i = startPage; i < endPage; i++) { pHtml += ‘<tr><td>‘; pHtml += (i+1) + ‘</td><td>‘; pHtml += libObj[i].name + ‘</td><td>‘; pHtml += libObj[i].libsNum + ‘</td></tr>‘; } libShow.html(pHtml); } }) } 完整代码 1. 前端 $(function () { var query = $(‘.query‘), rank = $(‘.rank‘), show = $(‘.show‘), queryLib = $(‘.queryLib‘), libShow = $(‘#libShow‘), libName = $(‘.libName‘), displayResult = $(‘.displayResult‘); var checkLib = (function(){ function _query(){ query.click(function(){ $.post( ‘/query‘, { rank: rank.val(), }, function(data){ console.log(data); } ) }); queryLib.click(function(){ var inputLibName = libName.val(); if (inputLibName.length == 0) { alert(‘请输入库名~‘); return; } $.post( ‘/queryLib‘, { libName: inputLibName, }, function(data){ if(data.length == 0){ alert(‘没有盘问到名为‘ + inputLibName + ‘的库‘); libName.val(‘‘); libName.focus(); libShow.html(‘‘) return; } var libHtml = ‘‘; for (var i = 0; i < data.length; i++) { libHtml += ‘<tr><td>‘; libHtml += (i+1) + ‘</td><td>‘; libHtml += data[i].name + ‘</td><td>‘; libHtml += data[i].libsNum + ‘</td></tr>‘; } libShow.html(libHtml); } ) }); } function _showLibs(){ show.click(function(){ $.get( ‘/getLibs‘, { rank: rank.val(), }, function(data){ console.log(‘一共返回‘+ data.length + ‘条数据‘); console.log(data) var libHtml = ‘‘; for (var i = 0; i < 20; i++) { libHtml += ‘<tr><td>‘; libHtml += (i+1) + ‘</td><td>‘; libHtml += data[i].name + ‘</td><td>‘; libHtml += data[i].libsNum + ‘</td></tr>‘; } displayResult.show(); libShow.html(libHtml);// 点击显示按钮,显示前20项数据 _paging(data); } ) }); } //翻页器 function _paging(libObj) { var ele = $(‘#page‘); var pages = Math.ceil(libObj.length/20); console.log(‘总页数‘ + pages); ele.bootstrapPaginator({ currentPage: 1, totalPages: pages, size:"normal", bootstrapMajorVersion: 3, alignment:"left", numberOfPages:pages, itemTexts: function (type, page, current) { switch (type) { case "first": return "首页"; case "prev": return "上一页"; case "next": return "下一页"; case "last": return "末页"; case "page": return page; } }, onPageClicked: function(event, originalEvent, type, page){ // console.log(‘当前选中第:‘ + page + ‘页‘); var pHtml = ‘‘; var endPage; var startPage = (page-1) * 20; if (page < pages) { endPage = page * 20; }else{ endPage = libObj.length; } for (var i = startPage; i < endPage; i++) { pHtml += ‘<tr><td>‘; pHtml += (i+1) + ‘</td><td>‘; pHtml += libObj[i].name + ‘</td><td>‘; pHtml += libObj[i].libsNum + ‘</td></tr>‘; } libShow.html(pHtml); } }) } function init() { _query(); _showLibs(); } return { init: init } })(); checkLib.init(); }) 2.后端路由 var express = require(‘express‘); var mongoose = require(‘mongoose‘); var request = require(‘request‘); var cheerio =require(‘cheerio‘); var router = express.Router(); var JsLib = require(‘../model/jsLib‘) /* 显示主页 */ router.get(‘/‘, function(req, res, next) { res.render(‘index‘); }); // 显示库 router.get(‘/getLibs‘,function(req,res,next){ JsLib.find({}) .sort({‘libsNum‘: -1}) .exec(function(err,data){ res.json(data); }) }) // 库的盘问 router.post(‘/queryLib‘,function(req,res,next){ var libName = req.body.libName; JsLib.find({ name: libName }).exec(function(err,data){ if (err) console.log(‘盘问呈现错误‘ + err); res.json(data); }) }) router.post(‘/query‘,function(req,res,next) { var rank = req.body.rank; var len = Math.round(rank/20); for (var i = 1; i < len+1; i++) { (function(i){ var options = { url: ‘‘ + i, headers: { ‘User-Agent‘: ‘Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36‘ } }; request(options, function (err, response, body) { analyData(body,rank); }) })(i) } res.json(‘生存告成‘) }) var sites = []; var flag = 0; function analyData(data,rank) { if(data.indexOf(‘html‘) == -1) return false; var $ = cheerio.load(data);// 通报 HTML var sitesArr = $(‘.info-wrap .domain-link a‘).toArray();//将所有a链接存为数组 console.log(‘网站爬取中``‘) for (var i = 0; i < 10; i++) { // ***这里后面要改,默认爬取前10名 var url = sitesArr[i].attribs.href; sites.push(url);//生存网址,添加wwww前缀 } console.log(sites); console.log(‘一共爬取‘ + sites.length +‘个网站‘); console.log(‘存储数据中...‘) getScript(sites); } // 获取JS库文件地点 function getScript(urls) { var scriptArr = []; var src = []; var jsSrc = []; for (var j = 0; j < urls.length; j++) { (function(i,callback){ var options = { url: urls[i], headers: { ‘User-Agent‘: ‘Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36‘ } } request(options, function (err, res, body) { if(err) console.log(‘呈现错误: ‘+err); var $ = cheerio.load(body); var scriptFile = $(‘script‘).toArray(); callback(scriptFile,options.url); }) })(j,storeLib) }; function storeLib(scriptFile,url){ flag++;// 是否存储数据的标识表记标帜 scriptFile.forEach(function(item,index){ if (item.attribs.src != null) { obtainLibName(item.attribs.src,index); } }) function obtainLibName(jsLink,i){ var reg = /[^\/\\]+$/g; var libName = jsLink.match(reg).join(‘‘); var libFilter = libName.slice(0,libName.indexOf(‘.‘)); src.push(libFilter); } // console.log(src.length); // console.log(calcNum(src).length) (function(len,urlLength,src){ // console.log(‘length is ‘+ len) if (len == 10 ) {// len长度为url的长度才向src和数据库里存储数据,防备反复储存 // calcNum(src);//存储数据到数据库 // ***这里后面要改,默认爬取前10名 var libSrc = calcNum(src); store2db(libSrc); } })(flag,urls.length,src) } }// getScript END // 将缓存数据存储到数据库 function store2db(libObj){ console.log(libObj); for (var i = 0; i < libObj.length; i++) { (function(i){ var jsLib = new JsLib({ name: libObj[i].lib, libsNum: libObj[i].num }); JsLib.findOne({‘name‘: libObj[i].lib},function(err,libDoc){ if(err) console.log(err); // console.log(libDoc) if (!libDoc){ jsLib.save(function(err,result){ if(err) console.log(‘生存数据堕落‘ + err); }); } }) })(i) } console.log(‘一共存储‘ + libObj.length + ‘条数据到数据库‘); } // JS库排序算法 function calcNum(arr){ var libObj = {}; var result = []; for (var i = 0, len = arr.length; i < len; i++) { if (libObj[arr[i]]) { libObj[arr[i]] ++; } else { libObj[arr[i]] = 1; } } for(var o in libObj){ result.push({ lib: o, num: libObj[o] }) } result.sort(function(a,b){ return b.num - a.num; }); return result; } module.exports = router; 跋文

温馨提示: 本文由Jm博客推荐,转载请保留链接: https://www.jmwww.net/file/web/31278.html