原文:
前端乱炖 http://www.html-js.com/article/2558
说明:
原文中的API可能比较旧,最新版的superagent会有执行错误,在原文基础上代码修改了一些
目标
-
获取
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(err, res) { if (err || !res.ok){ console.log('ERROR!!!!') } else{ //赋值给reptile.text,就会触发回调 that.text = res.text } }) }, //触发的回调函数在这里 text: function(text) { var that = this //cheerio 的 load 方法返回的对象,拥有与jQuery相似的API var $ = cheerio.load(text) var postList = [] //根据html结构,筛选所需部分 //这个页面我们只要标题跟对应的url。这里Blog_table1和Blog_td1是class属性名,a指的是a标签 $(".Blog_table1").find('.Blog_td1 a').each(function(i, e) { 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(err, res) { if (err || !res.ok) { console.log(res) } else { //我们在这里构造filename,指定了具体路径 that.content = { filename: path.join(cwd, 'postList', postItem.title + '.txt'), title: postItem.title, text: res.text } } }) }, //在这里处理每篇文章的具体内容 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文件