珠峰培训node培训之MongoDB+Express+Angular+Node+Bootstrap+Linux开发的爬虫

作者:日期:2016-08-12 17:21:42 点击:291

1. 网络爬虫

网络爬虫是一种自动获取网页内容的程序,功能如下

  1. 发出HTTP请求获取指定URL中的内容
  2. 使用jQuery的语法操作网页元素,提取需要的元素
  3. 将数据保存到mysql数据库中
  4. 建立web服务器显示这些数据
  5. 使用计划任务自动执行更新任务
  6. 布署项目到阿里云中并配置反向代理

2. 预备知识

2.1 request

一个简单的HTTP请求工具,用来获取网页内容

request

var request = require('request'); var iconv = require('iconv-lite'); request({url: 'http://top.baidu.com/category?c=10&fr=topindex' , encoding: null},function(err,response,body){     if(err)         console.error(err);     body = iconv.decode(body, 'gbk').toString();     var regex = /<a href=".\/buzz\?b=\d+&c=\d+">.+<\/a>/g;     console.log(body.match(regex)); }) 

2.2 cheerio

在服务器端实现了jQuery中的DOM操作API

cheerio

var cheerio = require('cheerio'); var $ = cheerio.load('<ul> <li><a href="./buzz?b=353&c=10">玄幻奇幻</a></li> \<li><a href="./buzz?b=354&c=10">爱情</a></li></ul>'); $('ul li a').each(function () {     var $me = $(this);     var item = {         name: $me.text().trim(),         url: $me.attr('href').slice(2)     }     var result = item.url.match(/buzz\?b=(\d+)/);     if (Array.isArray(result)) {         item.id = result[1];     }     console.log(item); }); 

2.3 cron

用来周期性的执行某种任务或等待处理某些事件的一个守护进程

cron

符号 含义
星号(*) 代表所有可能的值
逗号(,) 可以用逗号隔开的值指定一个列表范围,例如,“1,2,5,7,8,9”
中杠(-) 可以用整数之间的中杠表示一个整数范围,例如“2-6”表示“2,3,4,5,6”
正斜线(/) 可以用正斜线指定时间的间隔频率,*/10,如果用在minute字段,表示每十分钟执行一次
var cronJob = require('cron').CronJob; var job1 = new cronJob("* * * * * *",function(){   console.log('每秒'); }); job1.start(); 

2.4 debug

根据环境变量的有选择向控制台输出调试信息

debug

var debug = require('debug')('crawler:main'); //windows set DEBUG=crawler:* //linux export DEBUG=crawler:* debug('welcome to zhufengpeixun'); 

2.5 child_process

child_process即子进程可以创建一个系统子进程并执行shell命令

spawn语法

child_process.spawn(cmd, args=[], [options]) 

示例

var url = require('url'); var fs = require('fs'); var DOWNLOAD_DIR = './'; var spawn = require('child_process').spawn; // 使用curl下载文件的函数 var download_file_curl = function(file_url) {     // 提取文件名     var file_name = url.parse(file_url).pathname.split('/').pop();     // 创建一个可写流的实例     var file = fs.createWriteStream(DOWNLOAD_DIR + file_name);     // 使用spawn运行curl     var curl = spawn('curl', [file_url]);     // 为spawn实例添加了一个data事件     curl.stdout.on('data', function(data) { file.write(data); });     // 添加一个end监听器来关闭文件流     curl.stdout.on('end', function(data) {         file.end();         console.log(file_name + ' downloaded to ' + DOWNLOAD_DIR);     });     // 当子进程退出时,检查是否有错误,同时关闭文件流     curl.on('exit', function(code) {         if (code != 0) {             console.log('Failed: ' + code);         }     }); };  download_file_curl('http://pic.baidu.jpg'); 

exec语法

child_process.exec(cmd, [options], callback) 

示例

var url = require('url'); var fs = require('fs'); var DOWNLOAD_DIR = './'; var exec = require('child_process').exec; var download_file_curl = function(file_url) {     // 提取文件名     var file_name = url.parse(file_url).pathname.split('/').pop();      // 使用exec执行curl命令     var child = exec('curl '+file_url+' -o '     +DOWNLOAD_DIR+file_name, function(err, stdout, stderr) {         if (err) throw err;         else console.log(file_name + ' downloaded to ' + DOWNLOAD_DIR);     }); }; download_file_curl('http://pic.baidu.jpg'); 

2.6 async

async是一个流程控制库,为我们带来了丰富的嵌套解决方案

async

2.6.1 串行执行

串行执行一个函数数组中的每个函数 series(tasks,callback);

async.series([function(callback){         callback(null, "tv is over");     },function(callback){         callback(null, 'homework is down');     }],function(err, results) {     console.log(results); }); 

2.6.2 并行执行

parallel函数是并行执行多个函数,每个函数都是立即执行,不需要等待其它函数先执行 parallel(tasks, [callback])

console.time('start'); async.parallel([         function (callback) {             setTimeout(function () {                 callback(null, 'one');             },2000);         },         function (callback) {             setTimeout(function () {                 callback(null, 'two');             },3000);         }     ],     function (err, results) {         console.log(results);         console.timeEnd('start');     }); 

2.6.3 waterfall(瀑布)

waterfall和series函数有很多相似之处,都是按顺序依次执行一组函数,不同之处是waterfall每个函数产生的值,都将传给下一个函数 waterfall(tasks, [callback])

async.waterfall([function(callback){         callback(null, "水");     },function(data,callback){         callback(null, data+'+咖啡');     },function(data,callback){     callback(null, data+'+牛奶'); }],function(err, results) {     console.log(results);//水+咖啡+牛奶 }); 

2.6.4 自动依赖

用来处理有依赖关系的多个任务的执行 auto(tasks, [callback]);

async.auto({     getWater: function(callback){         callback(null, 'Water');     },     getFlour: function(callback){         callback(null, 'Flour');     },     mixFlour: ['getWater', 'getFlour', function(callback, results){         callback(null, results['getWater']+','         +results['getFlour']+','+'mixFlour');     }],     steam: ['mixFlour', function(callback, results){         callback(null, results['mixFlour']+',steam');     }] }, function(err, results) {     console.log('err = ', err);     console.log('results = ', results); }); 

注意callback, results的顺序在不同的async版本中不一样

2.6.5 迭代多个异步任务

所有的任务都迭代完成后才执行后续任务

var arr = [{name:'zfpx1'},{name:'zfpx2'}]; async.forEach(arr, function(item, callback) {     console.log('1.1 enter: ' + item.name);     setTimeout(function(){         console.log('1.1 handle: ' + item.name);         callback(null);     }, 1000); }, function(err,result) {     console.log('1.1 err: ' + err); }); 

3.实现爬虫

3.1 抓取内容

3.1.1 读取内容

tasks/read.js

var request = require('request'); var cheerio = require('cheerio'); var debug = require('debug')('crawler:read'); var iconv = require('iconv-lite'); module.exports =  function (url, callback) {     var items = [];     debug('读取电影列表');     request({url:url,encoding:null},function(err,response,body){         body = iconv.decode(body,'gbk');         var $ = cheerio.load(body);         $('.keyword .list-title').each(function(){             var that = $(this);             var item = {                 name:that.text().trim(),                 url:that.attr('href')             }             items.push(item);             debug('读取电影 ',item);         });         callback(null,items);         debug('读取电影列表完毕');     }); } 

3.1.2 数据库操作

model/index.js

var mongoose = require('mongoose'); mongoose.connect('mongodb://123.57.143.189/zhufengcrawl'); exports.Movie =  mongoose.model('Movie',new mongoose.Schema({     name:String,     url:String })); 

3.1.3 保存内容

tasks/save.js

var async = require('async'); var Movie = require('../model').Movie; var debug = require('debug')('crawler:save');  module.exports = function(items,callback){     async.series([        function(callback){            debug('清空电影列表');            Movie.remove({},callback);        },        function(callback){            debug('保存电影列表');            async.forEach(items, function (item, next) {                debug('保存电影 ',item);                Movie.create(item,next);            }, callback);        }     ],function(err,result){         debug('保存电影完毕');         callback();     }) } 

3.1.4 入口文件

tasks/main.js

var read = require('./read'); var save = require('./save'); var async = require('async'); var debug = require('debug')('crawler:main'); debug('开始计划任务'); var movies = []; async.series([     function(done){         read('http://top.baidu.com/buzz?b=26&c=1&fr=topcategory_c1',function(err,items){             movies = items;             done();         });     },     function(done){         save(movies,done);     } ],function(err,result){     debug('结束计划任务');     process.exit(0); }) 

3.1.5 计划任务

app.js

var spawn = require('child_process').spawn; var cronJob = require('cron').CronJob; var path = require('path'); var job = new cronJob('* * * * * ',function(){     var update = spawn(process.execPath,[path.join(__dirname,'tasks/main.js')]);     update.stdout.pipe(process.stdout);     update.stderr.pipe(process.stderr);     update.on('close',function(code){         console.log(code);     });     update.on('error',function(code){         console.log(code);     }); }); job.start(); 

3.2 页面展示

3.2.1 启动应用

app.js

var express = require('express'); var app = express(); app.set('view engine', 'jade'); app.set('views', 'views'); var Movie = require('./model').Movie; app.get('/', function (req, res) {     Movie.find({}, function (err, movies) {         res.render('index', {             movies: movies         });     }); }); app.listen(9090);  var spawn = require('child_process').spawn; var cronJob = require('cron').CronJob; var path = require('path'); var job = new cronJob('* * * * * ',function(){     var update = spawn(process.execPath,[path.join(__dirname,'tasks/main.js')]);     update.stdout.pipe(process.stdout);     update.stderr.pipe(process.stderr);     update.on('close',function(code){         console.log(code);     });     update.on('error',function(code){         console.log(code);     }); }); job.start(); 

3.2.2 编写模板

doctype html html     head         title 电影风云榜         link(rel="stylesheet",href="//cdn.bootcss.com/bootstrap/3.3.5/css/bootstrap.min.css")     body         .container             .panel.panel-primary                 .panel-heading.text-center 电影风云榜                 .panel-body                     ul.list-group                         each movie in movies                             li.list-group-item                                 a(href="#{movie.url}")=movie.name 

4. 资源

项目源码

珠峰培训node培训之MongoDB+Express+Angular+Node+Bootstrap+Linux开发的爬虫

珠峰node培训使用MongoDB+Express+Angular+Node+Bootstrap开发聊天室

珠峰node培训使用MongoDB+Express+Aagular+Node+Bootstrap开发博客

上一篇: 珠峰node培训使用MongoDB+Express+Angular+Node+Bootstrap开发聊天室

下一篇: 什么是buffer及buffer常用方法