Node爬取简书首页文章

时间:2022-06-05 18:10:04

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('<h2 class="title">Hello world</h2>') //导入html
// 查询并修改dom树内容
$('h2.title').text('Hello there!')
$('h2').addClass('welcome')

mysql

mysql用于最后数据的写入,执行SQL插入工作,只执行sql插入

$ npm install mysql

目标分析

Node爬取简书首页文章

我们用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爬取简书首页文章

小结

感觉node编程就要经常考虑异步和回调,思维方式与Python,Java不同。例如get是一个异步的行为,之前博主按照惯例在最后关闭数据库连接,结果竟然在服务器响应之前数据库连接已经断开,导致后面数据写入出错。

填node的坑还是任重道远啊……