feedparser学习与实战——基于Node.js的Feed解析器

node-feedparser

这篇文章是我学习node-feedparser的时候所写的,前半部分是翻译了node-feedparser在github上的原文(英语很差,若是翻译有误,还请见谅。),当中也夹杂了一些本身解释;后半部分的实战是我结合 compressed.js ,同时本身在实际运用中的小结,如今拿出来和你们分享,但愿你们给予指正。html

文章信息

  • 时间 / 2017年3月9日node

  • 版本号git

    • Node.js: v6.10.0github

    • node-feedparser: v2.1.0npm

    • request: v2.79.0编程

    • iconv-lite: v0.4.15api

  • 项目地址 / https://github.com/danmactoug...数组

目录

  • Feedparser 基于Node.js的RSS,Atom,RDF强劲解析器bash

  • 如何安装异步

  • 用法

    • feedparser可选参数

  • 例子

  • API

  • feedparser解析后能获得什么?

    • meta属性列表

    • article属性列表

  • 贡献

  • License

  • 实战

    • 处理数据

    • 取得数据

    • 编码问题

    • 错误捕捉

Feedparser 基于Node.js的RSS,Atom,RDF强劲解析器

Feedparser是一个基于基于Node.js的强劲解析器,能够解析包括RSS,Atom和RDF信息

它有一对特性是你在其余的Feed解析器中不常见的:

  1. 它能够解析一些相对URL连接(例如Tim Bray's "ongoing"这个Feed)

  2. 它能够正确地解析一些XML命名空间(包含那些很是规的Feed——用主要的一些Feed元素来定义的很是规命名空间)

说明:对第二条的理解是,一般Feed的XML命名是固定的一些标签,可是Feedparser一样能够对一些很是规的XML进行解析,这就是强大之处。

如何安装

npm install feedparser

用法

这个例子能简要地示范feedparser的基本概念:

请注意在学习基本的示范的同时,也要学习简化的范例compressed.js文件,这样也可以让你更全面地开展工做。

var FeedParser = require('feedparser');
var request = require('request'); // 须要引入一个request,用于抓取Feed

var req = request('http://somefeedurl.xml')
var feedparser = new FeedParser([options]);

req.on('error', function (error) {
  // 解决任何的request请求错误
  // 这个是request包的错误提示
});

req.on('response', function (res) {
  var stream = this; // 这里的this是req(所请求request文件),是stream文件类型

  if (res.statusCode !== 200) {
    this.emit('error', new Error('Bad status code'));
  }
  else {
    stream.pipe(feedparser);
  }
});

feedparser.on('error', function (error) {
  // 处理feedparser的错误
  // 这个是feedparser包的错误提示
});

feedparser.on('readable', function () {
  // 此时已经获取到Feed信息,在这里能够进行你的操做了
  var stream = this; // 这里的this是feedparser, 也是stream文件类型
  var meta = this.meta; // 注意:这个meta是在feedparser的实例中一直能够得到。
  //Meta实际上是RSS等一些的元信息,在后面会介绍到,通常来讲Meta信息都是重复的。
  var item;

  while (item = stream.read()) {
    console.log(item);
    //在这里输出每一条Feed信息。
  }
});

feedparser可选参数

  • normalize:设置false让Feedparser的默认值失效。不管这个Feed的形式,这个参数都能将其解析成一个包含RSS2.0格式,正确属性的对象。序列化后的形式如如下所示(只进入第一层):

//经过bash输出:

属性名:rss:@  值:[object Object]
属性名:rss:title  值:[object Object]
属性名:rss:link  值:[object Object]
属性名:rss:author  值:[object Object]
属性名:rss:guid  值:[object Object]
属性名:rss:category  值:[object Object]
属性名:rss:pubdate  值:[object Object]
属性名:rss:comments  值:[object Object]
属性名:rss:description  值:[object Object]
属性名:meta  值:[object Object]
  • addmeta:设置false让Feedparser的默认值失效。让每个Feed的article信息都加入Meta信息。我的建议能够设置为true,通常来讲,每一个Feed的Meta信息都是惟一的,而article信息不一样,只要第一次获取Meta后,就能够只须要article信息。

  • feedurl:Feed的URL地址。FeedParser能很是优秀地处理相对url,可是一些Feed在使用相对url时,并不声明xml:base信息。尽管feedparser很是有效,可是在咱们处理feed和尝试着处理这些相对url以前,咱们仍然不能知道feed的url。若是咱们发现了feed的url,咱们将会返回并处理那些咱们已经获得的相对url,但这将会消耗一段时间(并不是很长)。若是你想要确信咱们不对相对url进行预处理(或者feedparser没法处理相对url),你应该设置feedurl选项,不然,你就当没看见过它吧~

  • resume_saxerror:设置false让Feedparser的默认值失效。这个选项可以抛出error中的SAXError错误,并自动进行后续的解析。在个人测试中,SAXErrors并不常错误,因此开启这个选项一般对你颇有帮助。若是你想要彻底掌握和处理错误,并在任意点停止解析feed的话,能够尝试用这个选项。

例子

在这里查看例子 examples

API

转换 Stream

Feedparser是一个stream转换器(关于stream你能够在nodejs官网阅读),从XML文件转换为Javascript的objects对象。

每个可读的区块都是一个对象,这个对象表明feed中的article信息。

发出的项目

  • meta - 被解析后,称做feed的 meta

  • error - 任什么时候候Feedparser发出的错误(包括SAXError, Feedparser error等)

feedparser解析后能获得什么?

Feedparser对每个Feed都会解析出 meta 和一个或更多的 articles

不论Feed的形式如何, meta 和每个 article 都包含一个RSS2.0规范同时加上规范化后的属性的信息流。举个例子,一个Atom feed会有一个 meta.description 属性,可是一样会有一个 meta['atom:subtitle'] 属性。

这个规范化后的属性是用于向用户提供一个规范的接口——当你不知道feed的形式,或者搞不清不一样feed形式之间的差别时,用这个接口就能够方便获取feed信息。不过当你须要原始信息的时候会依然会保留给你使用。此外,Feedparser还提供了一些大众化的命名空间扩展,例如 itunes , media , feedburnerpheedo 这些扩展。举例:若是一个feed的article同时包含了 itunes:imagemedia:thumbnail ,那么这两个的url地址都会保存到article的 image.url 属性中。

全部的属性都会进行初始化,设置为 null (空数组或者空对象都会有恰当的属性)。这个可以节省你不少时间来检查属性是否为 undefined ,例如,当你使用jade模板的时候。

除此以外,全部的属性(包含命名空间)都使用小写字母("xmlUrl" and
"pubDate"仍然提供向下兼容)。“好用”取代了“原生”——衷心但愿你能没必要为骆驼拼写法而烦恼。

若是你设置normalize为true,那么 metaarticletitledescription 属性都会将HTML标签剥离。若是你须要这些HTML元素,你能够从 meta['atom:subtitle']['#'] 这个属性取得。

meta属性列表

  • title

  • description

  • link (网站连接)

  • xmlurl

  • date (最近的日期)

  • pubdate (原始出版日期)

  • author

  • language

  • image (一个对象,包含 urltitle 属性)

  • favicon (favicon的连接——只提供给Atom feeds)

  • copyright

  • generator

  • categories (一个字符串数组)

article属性列表

  • title

  • description (一般是完整的标题内容)

  • summary (一般是文章摘录)

  • link

  • origlink

  • permalink

  • date

  • pubdate

  • author

  • guid

  • comments

  • image

  • categories

  • source

  • enclosures

  • meta

贡献

在这里查看全部代码 -> contributors

License

(The MIT License)

实战

处理数据

feedparser.on('readable', function() {
  var item;
  while (item = this.read()) {
    //通常咱们在这里获取数据,在上面提到的,feedparser一共会输出两种信息,一种是规范化后的RSS2.0,另外一种是原有的。
    //原有信息的获取:(推荐这种)
    console.log(item.meta.title);
    console.log(item.title);
    //RSS2.0信息的获取:
    console.log(item['meta']['rss:title']['#']);
    console.log(item['rss:title']['#']);
  }
});

须要注意的是你没法经过return将上述的数据从函数中取出,也没法经过在外定义变量,在内赋值取出。由于这里用到了异步编程的事件监听,全部的动做都是异步操做,若是经过上述两个办法取出的值都是undefined。那么如何取出这些数据?这里有两个办法:

取得数据

由于feedparser使用的是异步编程的办法,因此没法经过常规方法取出值,不过仍然有如下两种办法:

  • 直接在函数中进行操做

  • 使用Promise封装

/*
 *  在函数中直接进行操做再也不演示
 *  这里主要演示Promise封装
 */

new Promise((resolve, reject)=>{
    //这里是一些request操做代码,暂时省略

    feedparser.on('readable', function() {
      var item;
      while (item = this.read()) {
        resolve(item);
      }
}).then((result)=>{
  //在这里能够用then继续操做
  console.log(result.title);
  //也能够return一个Promise对象,并在其余地方调用这个Promise。
  //但须要注意,在调用Promise的地方也须要异步编程
  return result;
}).catch((err)=>{
  console.log(err);
});

编码问题

在抓取非英文网页时,总会遇到编码问题,中文也不例外。好比新浪新闻的编码是"utf-8",可是腾讯新闻的编码是"gb3212"。feedparser虽然强大,但不负责解决这些问题,这个时候须要咱们引入 iconv-lite ,来解决编码问题。

var url = "http://www.example.xml";
var req = request(url);
var feedparser = FeedParser();
var encode = 'utf-8';

req.on('response', function (res) {
      console.log(res.statusCode); // 200
      console.log(res.headers['content-type']); // 'image/png'
    }).pipe(iconv.decodeStream(encode)) //在iconv-lite能够直接调用
    .pipe(feedparser);

由于 requestfeedparser 之间的通信是经过stream流的,而 iconv-lite 正好又有对于Stream流的API接口,因此直接调用便可。若是感兴趣或者有须要的同窗还能够去查看 iconv-lite官方文档查看其它的方法。

错误捕捉

在整个抓取Feed的过程当中,会遇到不少的错误,如何处理这些错误?这里借鉴一下官方文档所提到的 compressed.js 中的方法,它将全部的错误处理写成一个函数,而后在每次事件监听的地方,调用处理错误函数便可完成。

//错误处理函数:
function done(err) {
  if (err) {
    console.log(err, err.stack);
    return process.exit(1);
  }
  process.exit();
}

//事件监听调用done
// ...省略
  req.on('error', done);
  // ...省略
  feedparser.on('error', done);
  feedparser.on('end', done);
  feedparser.on('readable', function() {
    // ...省略
  });
相关文章
相关标签/搜索