Node.js 之 cherrio

cheerio是jquery核心功能的一個快速靈活而又簡潔的實現,主要是爲了用在服務器端需要對DOM進行操作的地方

簡介

cheerio是nodejs的抓取頁面模塊,爲服務器特別定製的,快速、靈活、實施的jQuery核心實現。適合各種Web爬蟲程序。

讓你在服務器端和html愉快的玩耍

var cheerio = require('cheerio'),
    $ = cheerio.load('<h2 class = "title">Hello world</h2>');

$('h2.title').text('Hello there!');
$('h2').addClass('welcome');

$.html();

安裝

npm install cheerio

特點

  • cheerio實現了jQuery的一個子集,去掉了jQuery中所有與DOM不一致或者是用來填瀏覽器的坑的東西,重現了jQuery最美妙的API
  • cheerio使用了及其簡潔而又標準的DOM模型, 因此對文檔的轉換,操作,渲染都極其的高效。基本的端到端測試顯示它的速度至少是JSDOM的8倍
  • cheerio使用了@FB55編寫的非常兼容的htmlparser2,因此它可以解析幾乎所有的HTML和XML

cheerio並非萬能,當你需要一個瀏覽器一樣的環境時,你最好還是用JSDOM,尤其是你需要進行自動化的功能測試時

關於JSDOM

jsdom是一個純粹由 javascript 實現的一系列 web標準,特別是 WHATWG 組織制定的DOM和 HTML 標準,用於在 nodejs 中使用。大體上來說,該項目的目標是模擬足夠的Web瀏覽器子集,以便用於測試和挖掘真實世界的Web應用程序。

  • JSDOM的解析規則太過於嚴格:JSDOM的解析器無法處理現在許多的流行網站的內容
  • JSDOM太慢了:解析大的網站甚至可以產生可察覺的延遲
  • JSDOM太過於重量級:JSDOM的目標是提供與瀏覽器一樣的DOM環境,但是我們往往不需要這樣。我們需要的只是一種簡單,熟悉的方式來操作我們的HTML

API

給定一段HTML

<ul id="fruits">
  <li class="apple">Apple</li>
  <li class="orange">Orange</li>
  <li class="pear">Pear</li>
</ul>

1. 解析html(load)

首先你需要先加載你的HTML。jQuery會自動完成這一步,因爲jQuery操作的DOM是固定的。但是在使用cheerio時我們要手動加載我們的HTML文檔

首選的方式如下:

var cheerio = require('cheerio'),
$ = cheerio.load('<ul id = "fruits">...</ul>');

其次,直接把HTML字符串作爲上下文也是可以的:

$ = require('cheerio');
$('ul', '<ul id = "fruits">...</ul>');

或者把HTML字符串作爲root

$ = require('cheerio');
$('li', 'ul', '<ul id = "fruits">...</ul>');

如果你需要自定義一些解析選項,你可以多傳遞一個對象給load方法:

$ = cheerio.load('<ul id = "fruits">...</ul>', {
    ignoreWhitespace: true,
    xmlMode: true
});

更多的解析選項可以參考domhandlerparser-options

2. 選擇器(selectors)

cheerio的選擇器幾乎和jQuery一模一樣,所以語法上十分相像

$( selector, [context], [root] )

selectorcontext的範圍內搜索,context的範圍又包含在root的範圍內。selectorcontext可以是一個字符串,DOM元素,DOM數組或者cheerio實例。root一般是一個HTML文檔字符串選擇器是文檔遍歷和操作的起點。如同在jQuery中一樣,它是選擇元素節點最重要的方法,但是在jQuery中選擇器建立在CSS選擇器標準庫上。cheerio的選擇器實現了大部分的方法

$('.apple', '#fruits').text()
//=> Apple
$('ul .pear').attr('class')
//=> pear
$('li[class=orange]').html()
//=> <li class = "orange">Orange</li>

3. 屬性操作(atrributes)

用來獲取和更改屬性的方法:

.attr(name, value)
這個方法用來獲取和設置屬性。獲取第一個符合匹配的元素的屬性值。如果某個屬性值被設置成null,那麼該屬性會被移除。你也可以把mapfunction作爲參數傳遞進去,就像在jQuery中一樣

$('ul').attr('id')
//=> fruits
$('.apple').attr('id', 'favorite').html()
//=> <li class = "apple" id = "favorite">Apple</li>

更多信息請查看 http://api.jquery.com/attr/

.removeAtrr(name)
移除名爲name的屬性

$('.pear').removeAttr('class').html()
//=> <li>Pear</li>

.hasClass(className)
檢查元素是否含有此類名

$('.pear').hasClass('pear')
//=> true
$('apple').hasClass('fruit')
//=> false
$('li').hasClass('pear')
//=> true

.addClass(className)
添加類名到所有的匹配元素,可以用函數作爲參數

$('.pear').addClass('fruit').html()
//=> <li class = "pear fruit">Pear</li>
$('.apple').addClass('fruit red').html()
//=> <li class = "apple fruit red">Apple</li>

參見 http://api.jquery.com/addClass/

.remoteClass([className])
移除一個或者多個(空格分隔)的類名,如果className爲空,則所有的類名都會被移除,可以傳遞函數作爲參數

$('.pear').removeClass('pear').html()
//=> <li class = "">Pear</li>
$('.apple').addClass('red').removeClass().html()
//=> <li class = "">Apple</li>

參見 http://api.jquery.com/removeClass/

遍歷

.find(selector)
在當前元素集合中選擇符合選擇器規則的元素集合

$('#fruits').find('li').length
//=> 3

.parent()
獲取元素集合第一個元素的父元素

$('.pear').parent().attr('id')
//=> fruits

.next()
選擇當前元素的下一個兄弟元素

$('.apple').next().hasClass('orange')
//=> true

**.prev().next()**相反

**.siblings()**獲取元素集合中第一個元素的所有兄弟元素,不包含它自己

$('.pear').siblings().length
//=> 2

.children( selector )
選擇指定的子元素

**.each( function(index, element) )**遍歷函數返回false即可終止遍歷

var fruits = [];
$('li').each(function(i, elem) {
  fruits[i] = $(this).text();
});
fruits.join(', ');
//=> Apple, Orange, Pear

.map( function(index, element) )

$('li').map(function(i, el) {
  // this === el
  return $(this).attr('class');
}).get().join(', ');
//=> apple, orange, pear

.filter( selector )

$('li').filter('.orange').attr('class');
//=> orange

.filter( function(index) )

$('li').filter(function(i, el) {
  // this === el
  return $(this).attr('class') === 'orange';
}).attr('class')
//=> orange

.first()

$('#fruits').children().first().text()
//=> Apple

.last()

$('#fruits').children().last().text()
//=> Pear

.eq( i )

縮小元素集合,可以用負數表示倒數第 i 個元素被保留

$('li').eq(0).text()
//=> Apple
$('li').eq(-1).text()
//=> Pear

操作DOM

操作DOM結構的方法

.append( content, [content, …] )
.prepend( content, [content, …] )
.after( content, [content, …] )

$('.apple').after('<li class = "plum">Plum</li>')
$.html()
//=>  <ul id = "fruits">
//      <li class = "apple">Apple</li>
//      <li class = "plum">Plum</li>
//      <li class = "orange">Orange</li>
//      <li class = "pear">Pear</li>
//    </ul>

.before( content, [content, …] )

$('.apple').before('<li class = "plum">Plum</li>')
$.html()
//=>  <ul id = "fruits">
//      <li class = "plum">Plum</li>
//      <li class = "apple">Apple</li>
//      <li class = "orange">Orange</li>
//      <li class = "pear">Pear</li>
//    </ul>

.remove( [selector] )

$('.pear').remove()
$.html()
//=>  <ul id = "fruits">
//      <li class = "apple">Apple</li>
//      <li class = "orange">Orange</li>
//    </ul>

.replaceWith( content )

var plum = $('<li class = "plum">Plum</li>')
$('.pear').replaceWith(plum)
$.html()
//=> <ul id = "fruits">
//     <li class = "apple">Apple</li>
//     <li class = "orange">Orange</li>
//     <li class = "plum">Plum</li>
//   </ul>

.empty()

$('ul').empty()
$.html()
//=>  <ul id = "fruits"></ul>

.html( [htmlString] )

$('.orange').html()
//=> Orange
$('#fruits').html('<li class = "mango">Mango</li>').html()
//=> <li class="mango">Mango</li>

.text( [textString] )

$('.orange').text()
//=> Orange
$('ul').text()
//=>  Apple
//    Orange
//    Pear

解析和渲染

$.html()
//=>  <ul id = "fruits">
//      <li class = "apple">Apple</li>
//      <li class = "orange">Orange</li>
//      <li class = "pear">Pear</li>
//    </ul>

輸出包含自己在內的HTML(outer HTML)

$.html('.pear')
//=> <li class = "pear">Pear</li>

常用工具

$.root()

$.root().append('<ul id="vegetables"></ul>').html();
//=> <ul id="fruits">...</ul><ul id="vegetables"></ul>

toArray()

$('li').toArray()
//=> [ {...}, {...}, {...} ]

.clone()

var moreFruit = $('#fruits').clone()

關注公衆號,獲取更多內容:
ercode1.png

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章