目标
获取
http://segmentfault.com/blogs/recommend?page=3
页面的文章列表postList
根据
postList
,逐个获取具体的文章页面用文章标题作为文件名,如:
{{ title }}.txt
;将文章内容储存在txt文件
中
工具或库的选择
superagent
可以便捷的发送网络请求,并得到其响应的结果cheerio
让我们可以用熟悉的jQuery
风格处理html
字符串observe.js
可以侦听对象的属性,被侦听的属性的值发生改变时,会自动调用指定回调函数,方便运用观察者模式
准备工作
- 分别加载需要的模块:
npm install superagent
npm install cheerio
npm install observe.js
- 新建文件
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')
具体实现
- 创建文件夹
postList
,用来储存txt文件
//以同步的方式:判断是否存在这个文件夹,不存在才创建
if (!fs.existsSync('postList')) {
fs.mkdirSync('postList')
}
//获取当前路径,方便读写目录跟文件
var cwd = process.cwd()
- 创建单例
//reptile 的意思是爬行动物、卑鄙的人。
//爬别人的内容,有点卑鄙的意味
var reptile = observe({})
- 侦听属性
//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()
}
})
}
})
- 初始化爬虫单例
reptile.url = 'http://segmentfault.com/blogs/recommend'
reptile.query = 'page=3'
以上,全部逻辑都写完.
运行app.js
在当前目录打开命令行,window系统下快捷方式为:按住shift
键,点击鼠标右键,菜单栏会多出在此处打开命令窗口
node app.js
等待结果,查看postList
目录下有无新增txt文件
web学习交流请与我联系
说个之前抓取不同编码网站时的问题(非node),页面要在抓取到后才知道编码格式,而设置编码需要在抓取前(抓取后转码有些乱码会丢失信息)……Node还没试过
@前端乱炖 。。。。。
@右Ctrl的记忆 作死,已封号