Node爬取简书首页文章

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

目标分析

我们用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的坑还是任重道远啊……

posted @ 2017-11-12 11:25  潇雨危栏  阅读(271)  评论(0编辑  收藏  举报