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() {
    // ...省略
  });
相關文章
相關標籤/搜索