Node爬取简书首页文章
博主刚学node,打算写个爬虫练练手,这次的爬虫目标是简书的首页文章
流程分析
- 使用superagent发送http请求到服务端,获取HTML文本
- 用cheerio解析获得的HTML文本,本例将解析简书首页20篇文章的基本信息
- 使用mysql模块把解析出的数据写入本地数据库存储
第三方模块
superagent
superagent是一个优雅又轻量级的网络请求API,类似于Python中的requests。官方文档在
$ npm install superagent
基本用法
Post请求
request .post('url') .send({ name: 'Manny', species: 'cat' }) //发送的数据 .set('X-API-Key', 'foobar') // set用来设置http请求头 .set('Accept', 'application/json') .end(function(err, res){ // 请求发送结束后监听服务器相应,注册回调函数 if (err || !res.ok) { alert('Oh no! error'); } else { alert('yay got ' + JSON.stringify(res.body)); } });// 链式写法request.post('/user') .send({ name: 'tj' }) .send({ pet: 'tobi' }) .end(callback)
Get请求
request .get('url') .query({ query: 'Manny', range: '1..5', order: 'desc' }) //加查询参数 .end(function(err, res){ // do something });// 链式写法request .get('/querystring') .query('search=Manny') .query('range=1..5') .end(function(err, res){ });
cheerio
cheerio是一个快速优雅的node解析库,可以再服务器端使用jQuery的方法完成dom操作,官方文档在
在本爬虫中,用于完成html解析查询的工作
$ npm install cheerio
基本用法
const cheerio = require('cheerio')const $ = cheerio.load('Hello world
') //导入html// 查询并修改dom树内容$('h2.title').text('Hello there!')$('h2').addClass('welcome')
mysql
mysql用于最后数据的写入,执行SQL插入工作,只执行sql插入
$ npm install mysql
目标分析
我们用firefox的开发者工具查看网页,目标是一个note-list下面的20个li,每个li是一篇文章,我们只要遍历20篇文章并且对于每个节点的内容进行解析即可
实现代码
const superagent = require('superagent')const cheerio = require('cheerio')const util =require('util')const mysql = require('mysql')// 定义爬取对象const reptileUrl = 'http://www.jianshu.com/'// 创建mysql数据库连接const connection = mysql.createConnection({ host:'localhost', user:'***', password:'***', database:'jianshu'})connection.connect()//发送请求superagent.get(reptileUrl).end(function (err, res) { // 错误拦截 if (err){ throw err } else{ // res.text是响应的原始html var $ = cheerio.load(res.text) var articleList = $("#list-container .note-list li") articleList.each(function(_, item){ //获取当前item var _this = $(item) // 文章名 var title = _this.find('.title').text().trim() // 作者 var nickname = _this.find('.nickname').text().trim() // 摘要 var abstract = _this.find('.abstract').text().trim() // 分类, 有些未分类的就分到『其他』 var tag = _this.find('.collection-tag').text().trim()||"其他" // 阅读量 var read = _this.find('.ic-list-read').parent().text().trim() // 评论数 var comment = _this.find('.ic-list-comments').parent().text().trim() // 点赞数 var like = _this.find('.ic-list-like').parent().text().trim() // 解析后把数据写入数据库 var base = "insert into articles " + "(title, nickname, abstract, tag, readNum, commentNum, likeNum)" + "values(%s,%s,%s,%s,%s,%s,%s)" var sql = util.format(base, "'"+title+"'", "'"+nickname+"'", "'"+abstract+"'", "'"+tag+"'", "'"+read+"'", "'"+comment+"'", "'"+like+"'") connection.query(sql, function (error, results) { if (error){ console.error(error) } else{ console.log(sql) } }) }) // 关闭数据库连接 connection.end() }})
运行结果
小结
感觉node编程就要经常考虑异步和回调,思维方式与Python,Java不同。例如get是一个异步的行为,之前博主按照惯例在最后关闭数据库连接,结果竟然在服务器响应之前数据库连接已经断开,导致后面数据写入出错。
填node的坑还是任重道远啊……