用nodejs抓取并存储网页内容
发布在前端细碎知识2015年1月27日view:8795from
在文章任何区域双击击即可给文章添加【评注】!浮到评注点上可以查看详情。

目标

  1. 获取http://segmentfault.com/blogs/recommend?page=3页面的文章列表postList

  2. 根据postList,逐个获取具体的文章页面

  3. 用文章标题作为文件名,如:{{ title }}.txt;将文章内容储存在txt文件

工具或库的选择

  1. superagent可以便捷的发送网络请求,并得到其响应的结果

  2. cheerio让我们可以用熟悉的jQuery风格处理html字符串

  3. observe.js可以侦听对象的属性,被侦听的属性的值发生改变时,会自动调用指定回调函数,方便运用观察者模式

准备工作

  1. 分别加载需要的模块:

npm install superagent
npm install cheerio
npm install observe.js

  1. 新建文件app.js,引入模块:
var superagent = require('superagent')
var observe = require('observe.js')
var cheerio = require('cheerio')
var path = require('path')
var url = require('url')
var fs = require('fs')

具体实现

  1. 创建文件夹postList,用来储存txt文件
//以同步的方式:判断是否存在这个文件夹,不存在才创建
if (!fs.existsSync('postList')) {
    fs.mkdirSync('postList')
}
//获取当前路径,方便读写目录跟文件
var cwd = process.cwd()
  1. 创建单例
//reptile 的意思是爬行动物、卑鄙的人。
//爬别人的内容,有点卑鄙的意味
var reptile = observe({})
  1. 侦听属性
//observe过的对象,有on off once hold collect tie等方法
//这里只用了on,根据属性名添加侦听函数
//用法跟jQuery.on类似,可以是对象批量侦听,可以逐个侦听reptile.on('url', callback)
reptile.on({
    //根据 url ,获取 text
    url: function(url) {
        var that = this
        //get方法发出请求,query方法为url添加query字段(url问号背后的)
        //end方法接受回调参数,html一般在res.text中
        superagent
            .get(url)
            .query(this.query)
            .end(function(res) {
                if (res.ok) {
                    //赋值给reptile.text,就会触发回调
                    that.text = res.text
                }
            })
    },
    //触发的回调函数在这里
    text: function(text) {
        var that = this
        //cheerio 的 load 方法返回的对象,拥有与jQuery相似的API
        var $ = cheerio.load(text)
        var postList = []
        //根据html结构,筛选所需部分
        //这个页面我们只要标题跟对应的url
        $('h2.title a').each(function() {
                postList.push({
                    title: $(this).text(),
                    url: path.join(url.parse(that.url).hostname, $(this).attr('href'))
                })
            })
        //赋值就触发回调
        this.postList = postList
        this.postItem = postList.shift()
    },
    //在这个回调里发出每一篇文章的请求
    postItem: function(postItem) {
        console.log(postItem.url)
        var that = this
        superagent
            .get(postItem.url)
            .end(function(res) {
                if (res.ok) {
                    //我们在这里构造filename,指定了具体路径
                    that.content = {
                        filename: path.join(cwd, 'postList', postItem.title + '.txt'),
                        title: postItem.title,
                        text: res.text
                    }
                } else {
                    console.log(res)
                }
            })
    },
    //在这里处理每篇文章的具体内容
    content: function(content) {
        var that = this
        var $ = cheerio.load(content.text)
        var data = ''
        //根据html结构选取正文,只要text部分,去掉html标签
        $('.article *').each(function() {
                data += $(this).text() + '\n'
            })
        //前面已经构造好了文件路径,直接写入即可
        fs.writeFile(content.filename, data, function(err) {
            if (err) {
                console.log(err)
            } else if (that.postList.length) {
                //写入完毕后,检查postList还有没有剩余
                //若有,取出来赋值给postItem,又goto到请求文章的步骤
                that.postItem = that.postList.shift()
            }
        })
    }
})
  1. 初始化爬虫单例
reptile.url = 'http://segmentfault.com/blogs/recommend'
reptile.query = 'page=3'

以上,全部逻辑都写完.

运行app.js

在当前目录打开命令行,window系统下快捷方式为:按住shift键,点击鼠标右键,菜单栏会多出在此处打开命令窗口

node app.js

等待结果,查看postList目录下有无新增txt文件

评论
发表评论
2年前
赞了此文章!
2年前
赞了此文章!
2年前
赞了此文章!
2年前
赞了此文章!
2年前
赞了此文章!
2年前

说个之前抓取不同编码网站时的问题(非node),页面要在抓取到后才知道编码格式,而设置编码需要在抓取前(抓取后转码有些乱码会丢失信息)……Node还没试过

2年前
添加了一枚【评注】:test
2年前
添加了一枚【评注】:test
2年前
添加了一枚【评注】:test
2年前
添加了一枚【评注】:test
2年前
添加了一枚【评注】:test
2年前
赞了此文章!
2年前
赞了此文章!
2年前
赞了此文章!
2年前

@前端乱炖 。。。。。

2年前

@右Ctrl的记忆 作死,已封号

2年前
赞了此文章!
2年前
赞了此文章!
WRITTEN BY
PUBLISHED IN
前端细碎知识

不定期输出前端细碎知识

我的收藏