用nodejs实现爬虫后使用mongodb存贮

记得3个月前,同样在csdn的博客上洋洋洒洒写了有几千字的文章,一个错点满满心血顷刻付之东流,后再也提不起写文章的兴趣了。

这些日子在捉摸着在自己的站上实现抓取网络文章收集后以供己用, 道德不道德的暂且不论。 君不见世面上大数据行业多火爆,其内容不也是采集各方数据么?

实现蜘蛛,对于前端来说,肯定使用自家专长语言 nodejs了。数据存储方面定了mongodb,不为别的,就为存取数据格式自由。

第一章节:安装mongodb

工欲善其事必先利其器,当然我们应首先搭建nodejs环境和安装mongodb了。 其中安装mongodb费了大半周折。 再次善意提醒各位新手,切莫尽信书的照mongodb官网上使用yum安装,国内的yum源根本就没有官网上最新的3.2*版本,最简单的方法就是直接下载编译后的源码包。地址:https://www.mongodb.com/download-center#community,下载完包后,解压缩。  解压后,mv 至 /usr/local/lib/下。然后建立服务启动命令软链至mongodb服务所在位置:

sudo ln -s /usr/local/lib/mongodb/bin/mongod /usr/local/bin/mongod 

sudo ln -s /usr/local/lib/mongodb/bin/mongo /usr/local/bin/mongo 

mongdb数据存储服务分为mongod服务端和mongo 客户端shell命令服务。建立软链后,我们可以开始启动mongod服务端的程序了,类同其它工具的工程化思维,一般软件都有一个配置项决定此软件的属性和设置,bin目录下的mongodb.conf,设置了mongodb的日志存放、数据存储、数据读取。。。等的相关配置。

需要注意的是网上所搜索到的大部分配置类似于 js声明方式的配置项是针对于 2.4*版本的。如:

#port=27027
#MongoDB数据文件目录
dbpath=/usr/local/mongodb/data
#MongoDB日志文件目录
logpath=/usr/local/mongodb/log/mongo.log
#日志文件自动累加
logappend=true

从2.6*版本开始,mongodb的配置采用了全新的yaml文件格式,参考官网说明:
File Format
IMPORTANT:
Changed in version 2.6: MongoDB 2.6 introduces a YAML-based configuration file format. The 2.4 configuration file 
format remains for backward compatibility.
MongoDB configuration files use the YAML format [1].
The following sample configuration file contains several mongod settings that you may adapt to your local configuration:
NOTE:
YAML does not support tab characters for indention: use spaces instead.


注意,yaml格式不支持tab缩进,请用空格代替。下面贴上我项目的配置文件:
systemLog:
  destination: file
  #指定是一个文件
  path: "/var/log/mongodb/"
  #日志存放位置
  logAppend: true
  #产生日志内容追加到文件
processManagement:
  fork: true
  #以守护进程的方式运行MongoDB,创建服务器进程
  pidFilePath: "/var/run/mongodb/mongodb.pid"
  #pid文件路径
net:
  bindIp: 127.0.0.1
  #绑定ip地址访问mongodb,多个ip逗号分隔
  port: 27017
  #端口
  maxIncomingConnections: 65536
  #默认65536,mongodb实例接受的最多连接数,如果高于操作系统接受的最大线程数,设置无效。
#  http:
#    enabled: true 
#http端口最好关闭
#RESTInterfaceEnabled: false
#即使http接口选项关闭,如果这个选项打开后会有更多的不安全因素
storage:
  dbPath: "/data/db"
  #数据文件存放路径
  engine: "wiredTiger"
  #数据引擎
  mmapv1:
    smallFiles: true
    nsSize: 16
    quota:
      maxFilesPerDB: 8
  wiredTiger:
    engineConfig:
    #wt引擎配置
      cacheSizeGB: 1
      #看服务器情况来进行设置
      directoryForIndexes: true
      #索引是否按数据库名进行单独存储
    collectionConfig:
      blockCompressor: zlib
      #压缩配置
    indexConfig:
      prefixCompression: true
      #索引配置
  journal:
    enabled: true
    #记录操作日志,防止数据丢失。
  directoryPerDB: true
  #指定存储每个数据库文件到单独的数据目录。如果在一个已存在的系统使用该选项,需要事先把存在的数据文件移动到目录。
operationProfiling:
  #slowOpThresholdMs: 100 
  #指定慢查询时间,单位毫秒,如果打开功能,则向system.profile集合写入数据
  mode: "slowOp"
  #off、slowOp、all,分别对应关闭,仅打开慢查询,记录所有操作。
security:
  #keyFile: "/data/mongodb-keyfile"
  #指定分片集或副本集成员之间身份验证的key文件存储位置
  #clusterAuthMode: "keyFile"
  #集群认证模式,默认是keyFile
  authorization: "disabled"
  #访问数据库和进行操作的用户角色认证
  #默认为磁盘的5%,指定oplog的最大尺寸。对于已经建立过oplog.rs的数据库,指定无效

mongod服务启动有两种方式,一种是启动时加载配置文件,另一种时启动时指定配置。

配置文件方式:mongod -f/--config /your mongodb.conf path

参数命令方式:mongod --dbpath /usr/lib/mongodb/data/db/ --logpath /var/log/mongodb/logs --fork

第二章节:mongo服务与mongodb的数据库概念

mongo是mongodb数据库的客户端shell命令窗口服务,想要启动mongo服务窗口,首先启动mongod服务。启动mongo服务后,我们就可以查看数据
库相关信息了:
[xiaoang@dev02v ~/git/web/site]$ mongo
MongoDB shell version: 3.2.7
connecting to: test
Server has startup warnings: 
2016-07-28T15:30:49.189+0800 I CONTROL  [initandlisten] 
2016-07-28T15:30:49.189+0800 I CONTROL  [initandlisten] ** WARNING: soft rlimits too low. The locked memory size is 32768 bytes, it should be at least 65536 bytes
> show dbs     //查看数据库列表
local                0.000GB
mydb                 0.000GB
mydb1                0.000GB
mydb2                0.000GB
node-mongo-examples  0.000GB
test                 0.000GB
> use mydb1   //进入mydb1数据库,并启用当前数据库操作权限,所以后续的操作就是在mydb1下的操作
switched to db mydb1
> show collections   //查看当前数据库的数据集合
movies
> db.movies.find()  //查看当前数据集合的数据
{ "_id" : ObjectId("57982cf5f40fb6d87061e865"), "ahref" : "", "__v" : 0 }
{ "_id" : ObjectId("57982dda620543107367b88b"), "ahref" : "", "__v" : 0 }
> 
mongodb数据库的存贮形式和概念与我们所熟悉的mysql是有些区别的, 下表将帮助您更容易理解Mongo中的一些概念:
SQL术语/概念 MongoDB术语/概念 解释/说明
database database 数据库
table collection 数据库表/集合
row document 数据记录行/文档
column field 数据字段/域
index index 索引
table joins   表连接,MongoDB不支持
primary key primary key 主键,MongoDB自动将_id字段设置为主键

通过下图实例,我们也可以更直观的的了解Mongo中的一些概念:

此节参考:http://www.runoob.com/mongodb/mongodb-tutorial.html

第三章节:蜘蛛程序与mongodb存储

蜘蛛程序的目的就是为了抓取网络数据为己所用,当然蜘蛛程序的话,不能单单抓取一个页面内容就称为蜘蛛,岂不遭人笑话。
我的项目也是单单抓取了一个我感兴趣的网站上的文章链接, 首先锁定你要抓取的网页的特性,发现其文章列表页翻页规则后,使用循环锁定你要
抓取的页面地址集合。
for(var i = 1; i <= pageNum; i++){
    pageUrls.push('http://www.**.com/post/?page='+i)
}

使用superagent模块实现http获取url内容,结合dom操作模块cheerio(类似于jquery的dom操作库),抓取你感兴趣的内容,然后使用mongoose
模块进行数据存储。
var http = require('http'),
    superagent = require('superagent'),
    cheerio = require('cheerio'),
    mongoose = require('mongoose'),
    mongourl = 'mongodb://localhost/mydb2',
    pageUrls = [],
    pageNum = 15;
for(var i = 1; i <= pageNum; i++){
    pageUrls.push('http://www.75team.com/post/?page='+i)
}
mongoose.connect(mongourl);
var Schema = mongoose.Schema;
//骨架模版
var movieSchema = new Schema({
    ahref : String
})
//模型
var Movie = mongoose.model('Movie', movieSchema);
//存储数据
pageUrls.forEach(function(pageUrl){
    superagent.get(pageUrl)
    .end(function(err,page){
        var $ = cheerio.load(page.text);
        var quoteUrls = $('.entry-content blockquote a');
        for(var i = 0;i < quoteUrls.length; i++){
            var articalUrl ='{ahref:"'+ quoteUrls.eq(i).attr("href") +'"},';
            var moive = new Movie({
                ahref : articalUrl
            })
            //保存数据库
            moive.save(function(err) {
                if (err) {
                    console.log('保存失败')
                    return;
                }                                                               
                console.log('meow');
            })
        }
    })
})

superagent很好的实现了http请求的处理,支持链式引用。 mongoose避免了使用原生mongodb程序不时的open和close操作,从而避免了频繁
的mongod服务挂掉。各模块的知识可以自行查看文档进行研习。
在此程序中有很大的不解地方,想实现定义一个数组,当每一个http请求url去爬取数据,再push到数组后,供后续使用,但无论如何都不能
达到效果,使用异步co模块亦不能。只能在每个 “superagent.get(pageUrl).end(function(err,page){” 回调里去直接输出或写入文件或
mongdb实时的去存储,很郁闷,因为这样会造成频繁的读写操作。 求高手解答。

第四章节:爬取后response或fs写入

在实现上章节的mongoose服务的存储后,感觉应该再考虑别的存储方式,于是直接response或fs模块写入文件一并印入脑海。

var http = require('http'),                                                                                                                                                                    
    url = require('url'),
    superagent = require('superagent'),
    cheerio = require('cheerio'),
    articalUrls = [], 
    pageUrls = [], 
    pageNum = 15; 
for(var i = 1; i <= pageNum; i++){
    pageUrls.push('http://www.***.com/post/?page='+i)
}
function onRequest(req,res){
    res.writeHead(200,{'Content-Type':'text/html;charset=utf-8'});
    pageUrls.forEach(function(pageUrl,j){
        superagent.get(pageUrl)
        .end(function(err,page){
            var $ = cheerio.load(page.text);
            var quoteUrls = $('.entry-content blockquote a');
            for(var i = 0;i < quoteUrls.length; i++){
                var articalUrl = quoteUrls.eq(i).attr('href');
                articalUrls.push(articalUrl);
            }   
            if(j == 14){
                res.write('<img src="http://img.zcool.cn/community/01013d56ebaea86ac7257d204ec3c8.gif"/><br/>请等待,数据汇总中');
                setTimeout(function(){
                    res.end(JSON.stringify(articalUrls));
                },5000)
            }   
        })  
    })  
}
http.createServer(onRequest).listen(3000);
var http = require('http'),
    fs = require('fs'),
    superagent = require('superagent'),
    cheerio = require('cheerio'),
    dbtxt = '/home/xiaoang/git/web/site/static/data/article1.txt',
    pageUrls = [], 
    pageNum = 15; 
for(var i = 1; i <= pageNum; i++){
    pageUrls.push('http://www.***.com/post/?page='+i)
}
pageUrls.forEach(function(pageUrl,j){
    superagent.get(pageUrl)
    .end(function(err,page){
        var $ = cheerio.load(page.text);                                                                                                                                                       
        var quoteUrls = $('.entry-content blockquote a');
        for(var i = 0;i < quoteUrls.length; i++){
            var articalUrl ='{ahref:"'+ quoteUrls.eq(i).attr("href") +'"},';
            fs.writeFile(dbtxt, articalUrl,{'flag':'a'}, function (err) {
                if (err) throw err;
            })  
        }   
        if(j == 14) 
        console.log('It\'s saved!');
    })  
})
/*fs.readFile(dbtxt, 'utf-8', function(err, data) {
    if (err) {
        throw err;
    }
    console.log(data);
});*/



  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值