Node.js实战cheerio网页抓取器

网络抓取要识别Web页面,并将其转换成结构化数据。比如说,你要负责升级出版社那古老的静态网站,需要把之前的页面下载下来,经过分析后提取所有图书的书名、介绍、作者和售价。你肯定不想自己手工完成这项任务,所以决定写个Node程序来做这件事。这种程序就是网络抓取器。
                           —— 《Node.js实战》 (第2版) P267

Node.js实战 封面

找个出版社的静态网页,图灵社区不就是个正好的对象吗😄,那就以Node.js实战(第2版)这本书为例吧!


1、提取图书书名

详情页中图书名称HTML代码

<h2>
         Node.js实战(第2版)
</h2>

提取片段的cheerio代码如下

const html = `
    <h2>
             Node.js实战(第2版)
    </h2>
`;

const cheerio = require('cheerio');
const $ = cheerio.load(html);
console.log($('.book-title h2').text().trim());

2、提取简介

<div class="book-intro readmore">
                                    本书是Node.js的实战教程,涵盖了为开发产品级Node应用程序所需要的一切特性、技巧以及相关理念。 从搭建Node开发环境,到一些简单的演示程序,到开发复杂应用程序所必不可少的异步编程。第2版介绍了全栈开发者所需的全部技术,包括前端构建系统、选择Web框架、在Node中与数据库的交互、编写测试和部署Web程序,等等。 
                                </div>

提取代码如下

$('.book-intro').text().trim();

3、提取作者

上面两个比较简单,只是热热身,作者的提取就稍微有些麻烦了。

HTML代码

<div class="book-author">
                                <span>
[英] 亚历克斯•杨 等                                    (作者)
                                </span>
                                <span>
<a href="/space/87796">吴海星</a>                                    (译者)
                                </span>
                            </div>

可以看到有一个作者,有一个译者,怎么把他们分别提取出来呢。我们先看看下面的代码

console.log($('.book-author').children().length);

运行的结果是2,说明在book-author这个节点下面有两个子节点,这与我们看到的HTML代码相符。

用一个each函数遍历,并把它们分别打印出来:

$('.book-author').children().each((i, e)=>{
  console.log($(e).text().trim());
});

再做些进一步的处理

$('.book-author').children().each((i, e)=>{
  
  let 名字 = $(e).text().trim();
  if (名字.indexOf('(作者)')  != -1) {
    console.log('作者:', 名字.replace(/\(作者\)/, '').trim());
  }

  if (名字.indexOf('(译者)')  != -1) {
    console.log('译者:', 名字.replace(/\(译者\)/, '').trim());
  }
});

完整代码

const superagent = require('superagent');
const cheerio = require('cheerio');

const url = 'http://www.ituring.com.cn/book/1993';

superagent.get(url).end( function(err, res) {
    // 抛错拦截
    if (err) {
        return
        throw Error(err)
    }

    const book = {};

    let $ = cheerio.load(res.text,{
        decodeEntities: false
    });

    book.title = $('.book-title h2').text().trim();

    book.intro = $('.book-intro').text().trim();

    book.status = 出版状态 = $('li:contains("出版状态")').text().replace(/出版状态/, '');

    $('.book-author').children().each((i, e)=>{
  
        let 名字 = $(e).text().trim();
        if (名字.indexOf('(作者)')  != -1) {
          book.auther = 名字.replace(/\(作者\)/, '').trim();
        }
      
        if (名字.indexOf('(译者)')  != -1) {
          book.translator = 名字.replace(/\(译者\)/, '').trim();
        }
    });

    let 定价 = $('li:contains("定  价")').text().replace(/定  价/, '');

    if (定价) {
        book.price = 定价;

        let 有电子书 = false;
        
        let 找电子书 = $('dt').filter( function() {
            let 有吗 = $(this).text().trim() === '电子书';
            if (有吗 === true) {
                有电子书 = true;
                return true;
            }
        });

        if (有电子书) {
            book.ePrice = 找电子书.next().children('.price').text().trim();
        }
    }

    book.tags = [];

    $('.post-tag').each((i, e)=>{
        book.tags.push($(e).text());
    });

    console.log(book);
});
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • Node.js第一天 1. 初识Node.js 1.1 Node.js是什么 Node.js® is a Java...
    再见天才阅读 4,817评论 1 24
  • 弟兄们,我还有话说:我们靠着主耶稣求你们,劝你们,你们既然受了我们的教训,知道该怎样行可以讨神的喜悦,就要照你们现...
    澳新好物种草阅读 2,126评论 0 0
  • 昨晚亲爸喝醉酒给于朵打电话。 谈了很多事情,直到夜里十点。后来姐和妹也加入进来。 他很开心,看样子是吧。他眼神很温...
    笠早阅读 322评论 0 1
  • 妹妹应聘某银行大堂经理失败,回来和我说面试的事。 第一关面试应该是看颜值吧,毕竟银行这种窗口单位,颜值放在首位也不...
    恋枫林阅读 1,739评论 0 4
  • 云在他乡常做客 月留一半照故乡 思亲辛苦心憔悴 深夜无眠空自伤
    白鹤来翔阅读 64评论 0 0