這篇文章是我學習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信息
它有一對特性是你在其餘的Feed解析器中不常見的:
它能夠解析一些相對URL連接(例如Tim Bray's "ongoing"這個Feed)
它能夠正確地解析一些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信息。 } });
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
。
Feedparser是一個stream轉換器(關於stream你能夠在nodejs官網閱讀),從XML文件轉換爲Javascript的objects對象。
每個可讀的區塊都是一個對象,這個對象表明feed中的article信息。
meta
- 被解析後,稱做feed的 meta
error
- 任什麼時候候Feedparser發出的錯誤(包括SAXError, Feedparser error等)
Feedparser對每個Feed都會解析出 meta
和一個或更多的 articles
。
不論Feed的形式如何, meta
和每個 article
都包含一個RSS2.0規範同時加上規範化後的屬性的信息流。舉個例子,一個Atom feed會有一個 meta.description
屬性,可是一樣會有一個 meta['atom:subtitle']
屬性。
這個規範化後的屬性是用於向用戶提供一個規範的接口——當你不知道feed的形式,或者搞不清不一樣feed形式之間的差別時,用這個接口就能夠方便獲取feed信息。不過當你須要原始信息的時候會依然會保留給你使用。此外,Feedparser還提供了一些大衆化的命名空間擴展,例如 itunes
, media
, feedburner
和 pheedo
這些擴展。舉例:若是一個feed的article同時包含了 itunes:image
或 media:thumbnail
,那麼這兩個的url地址都會保存到article的 image.url
屬性中。
全部的屬性都會進行初始化,設置爲 null
(空數組或者空對象都會有恰當的屬性)。這個可以節省你不少時間來檢查屬性是否爲 undefined
,例如,當你使用jade模板的時候。
除此以外,全部的屬性(包含命名空間)都使用小寫字母("xmlUrl" and
"pubDate"仍然提供向下兼容)。「好用」取代了「原生」——衷心但願你能沒必要爲駱駝拼寫法而煩惱。
若是你設置normalize爲true,那麼 meta
和 article
的 title
和 description
屬性都會將HTML標籤剝離。若是你須要這些HTML元素,你能夠從 meta['atom:subtitle']['#']
這個屬性取得。
title
description
link (網站連接)
xmlurl
date (最近的日期)
pubdate (原始出版日期)
author
language
image (一個對象,包含 url
和 title
屬性)
favicon (favicon的連接——只提供給Atom feeds)
copyright
generator
categories (一個字符串數組)
title
description (一般是完整的標題內容)
summary (一般是文章摘錄)
link
origlink
permalink
date
pubdate
author
guid
comments
image
categories
source
enclosures
meta
在這裏查看全部代碼 -> contributors。
(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);
由於 request
和 feedparser
之間的通信是經過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() { // ...省略 });