cheerio是一個(gè)node的庫(kù),可以理解為一個(gè)Node.js版本的jquery,用來(lái)從網(wǎng)頁(yè)中以 css selector取數(shù)據(jù),使用方式和jquery基本相同。
本文是cherrio官方教程的翻譯。
let cheerio = require('cheerio')
let $ = cheerio.load('<h2 class="title">Hello world</h2>')
$('h2.title').text('Hello there!')
$('h2').addClass('welcome')
$.html()
//=> <h2 class="title welcome">Hello there!</h2>
特性
- 相似的語(yǔ)法:Cheerio 包括了 jQuery 核心的子集。Cheerio 從jQuery庫(kù)中去除了所有 DOM不一致性和瀏覽器尷尬的部分,揭示了它真正優(yōu)雅的API。
- 閃電般的塊:Cheerio 工作在一個(gè)非常簡(jiǎn)單,一致的DOM模型之上。解析,操作,呈送都變得難以置信的高效。基礎(chǔ)的端到端的基準(zhǔn)測(cè)試顯示Cheerio 大約比JSDOM快八倍(8x)。
- 巨靈活: Cheerio 封裝了兼容的htmlparser。Cheerio 幾乎能夠解析任何的 HTML 和 XML document。
API
<ul id="fruits">
<li class="apple">Apple</li>
<li class="orange">Orange</li>
<li class="pear">Pear</li>
</ul>
這是我們將會(huì)在所有的API例子中用到的HTML標(biāo)記
Loading
首先你需要加載HTML。這一步對(duì)jQuery來(lái)說(shuō)是必須的,通過Cheerio,我們需要把HTML document 傳進(jìn)去。
這是首選:
var cheerio = require('cheerio'),
$ = cheerio.load('<ul id="fruits">...</ul>');
或者通過傳遞字符串作為內(nèi)容來(lái)加載HTML:
$ = require('cheerio');
$('ul', '<ul id="fruits">...</ul>');
Or as the root:
$ = require('cheerio');
$('li', 'ul', '<ul id="fruits">...</ul>');
你也可以傳遞一個(gè)額外的對(duì)象給.load()如果你需要更改任何的默認(rèn)解析選項(xiàng)的話:
$ = cheerio.load('<ul id="fruits">...</ul>', {
normalizeWhitespace: true,
xmlMode: true
});
這些解析選項(xiàng)都是直接來(lái)自htmlparser ,因此任何在htmlparser里有效的選項(xiàng)在Chreeio里也是行得通的。默認(rèn)的選項(xiàng)如下:
{
withDomLvl1: true,
normalizeWhitespace: false,
xmlMode: false,
decodeEntities: true
}
想看選項(xiàng)清單和它們都效果,看這個(gè)和這個(gè)
Selectors
Cheerio的選擇器用起來(lái)幾乎和jQuery一樣,所以API也很相似。
$(selectior,[context],[root])
選擇器在 Context 范圍內(nèi)搜索,Context又在Root范圍內(nèi)搜索。注意:這里是root在右,context在左。selector 和context可以是一個(gè)字符串表達(dá)式,DOM元素,和DOM元素的數(shù)組,或者chreeio對(duì)象。root 是通常是HTML 文檔字符串。
$('.apple', '#fruits').text()
//=> Apple
//id為fruits,class為apple的元素,先root后context
$('ul .pear').attr('class')
//=> pear
//class為pear的ul元素
$('li[class=orange]').html()
//=> Orange
//class屬性為orange的li元素
Attributes
.attr(name,value)
獲得和修改屬性。在匹配的元素中只能獲得第一元素的屬性。如果設(shè)置一個(gè)屬性的值為null,則移除這個(gè)屬性。你也可以傳遞一對(duì)鍵值,或者一個(gè)函數(shù)。
$('ul').attr('id')
//=> fruits
$('.apple').attr('id', 'favorite').html()
//=> <li class="apple" id="favorite">Apple</li>
更多信息請(qǐng)看這里
.prop( name, value )
Method for getting and setting properties. Gets the property value for only the first element in the matched set.
$('input[type="checkbox"]').prop('checked')
//=> false
$('input[type="checkbox"]').prop('checked', true).val()
//=> ok
See http://api.jquery.com/prop/ for more information
.data( name, value )
Method for getting and setting data attributes. Gets or sets the data attribute value for only the first element in the matched set.
$('<div data-apple-color="red"></div>').data()
//=> { appleColor: 'red' }
$('<div data-apple-color="red"></div>').data('apple-color')
//=> 'red'
var apple = $('.apple').data('kind', 'mac')
apple.data('kind')
//=> 'mac'
See http://api.jquery.com/data/ for more information
.val( [value] )
Method for getting and setting the value of input, select, and textarea. Note: Support for map
, and function
has not been added yet.
$('input[type="text"]').val()
//=> input_text
$('input[type="text"]').val('test').html()
//=> <input type="text" value="test"/>
.removeAttr(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)
增加class(es)給所有匹配的elements.也可以傳函數(shù)。
$('.pear').addClass('fruit').html()//=> <li class="pear fruit">Pear</li>$('.apple').addClass('fruit red').html()//=> <li class="apple fruit red">Apple</li>
更多信息看這里
.removeClass([className])
從選擇的elements里去除一個(gè)或多個(gè)有空格分開的class。如果className 沒有定義,所有的classes將會(huì)被去除,也可以傳函數(shù)。
$('.pear').removeClass('pear').html()//=> <li class="">Pear</li>$('.apple').addClass('red').removeClass().html()//=> <li class="">Apple</li>
更多信息看這里
.is.(selector)
.is(function(index))
有任何元素匹配selector就返回true。如果使用判定函數(shù),判定函數(shù)在選中的元素中執(zhí)行,所以this指向當(dāng)前的元素。
Traversing
.find(selector)
獲得一個(gè)在匹配的元素中由選擇器濾過的后代。
$('#fruits').find('li').length//=> 3
.parent([selector])
獲得每個(gè)匹配元素的parent,可選擇性的通過selector篩選。
$('.pear').parent().attr('id')//=> fruits
.parents([selector])
獲得通過選擇器篩選匹配的元素的parent集合。
$('.orange').parents().length// => 2$('.orange').parents('#fruits').length// => 1
.closest([selector])
對(duì)于每個(gè)集合內(nèi)的元素,通過測(cè)試這個(gè)元素和DOM層級(jí)關(guān)系上的祖先元素,獲得第一個(gè)匹配的元素
$('.orange').closest()// => []$('.orange').closest('.apple')// => []$('.orange').closest('li')// => [<li class="orange">Orange</li>]$('.orange').closest('#fruits')// => [<ul id="fruits"> ... </ul>]
.next()獲得第一個(gè)本元素之后的同級(jí)元素
$('.apple').next().hasClass('orange')//=> true
.nextAll()
獲得本元素之后的所有同級(jí)元素
$('.apple').nextAll()//=> [<li class="orange">Orange</li>, <li class="pear">Pear</li>]
.prev()
獲得本元素之前的第一個(gè)同級(jí)元素
$('.orange').prev().hasClass('apple')//=> true
.preAll()
$('.pear').prevAll()//=> [<li class="orange">Orange</li>, <li class="apple">Apple</li>]
獲得本元素前的所有同級(jí)元素
.slice(start,[end])
獲得選定范圍內(nèi)的元素
$('li').slice(1).eq(0).text()//=> 'Orange'$('li').slice(1, 2).length//=> 1
.siblings(selector)
獲得被選擇的同級(jí)元素,除去自己??
$('.pear').siblings().length//=> 2$('.pear').siblings('.orange').length//=> 1
.children(selector)
獲被選擇元素的子元素
$('#fruits').children().length//=> 3$('#fruits').children('.pear').text()//=> Pear
.each(function(index,element))
迭代一個(gè)cheerio對(duì)象,為每個(gè)匹配元素執(zhí)行一個(gè)函數(shù)。When the callback is fired, the function is fired in the context of the DOM element, so this refers to the current element, which is equivalent to the function parameter element.要提早跳出循環(huán),返回false.
var fruits = [];
$('li').each(function(i, elem) {
fruits[i] = $(this).text();
});
fruits.join(', ');
//=> Apple, Orange, Pear
.map(function(index,element))
迭代一個(gè)cheerio對(duì)象,為每個(gè)匹配元素執(zhí)行一個(gè)函數(shù)。Map會(huì)返回一個(gè)迭代結(jié)果的數(shù)組。the function is fired in the context of the DOM element, so this refers to the current element, which is equivalent to the function parameter element
$('li').map(function(i, el) { // this === el return $(this).attr('class');}).join(', ');//=> apple, orange, pear
.filter(selector)
.filter(function(index))
迭代一個(gè)cheerio對(duì)象,濾出匹配選擇器或者是傳進(jìn)去的函數(shù)的元素。如果使用函數(shù)方法,這個(gè)函數(shù)在被選擇的元素中執(zhí)行,所以this指向的手勢(shì)當(dāng)前元素。
Selector:
$('li').filter('.orange').attr('class');//=> orange
Function:
$('li').filter(function(i, el) { // this === el return $(this).attr('class') === 'orange';}).attr('class')//=> orange
.first()
會(huì)選擇chreeio對(duì)象的第一個(gè)元素
$('#fruits').children().first().text()//=> Apple
.last()
$('#fruits').children().last().text()//=> Pear
會(huì)選擇chreeio對(duì)象的最后一個(gè)元素
.eq(i)
通過索引篩選匹配的元素。使用.eq(-i)就從最后一個(gè)元素向前數(shù)。
$('li').eq(0).text()//=> Apple$('li').eq(-1).text()//=> Pear
Manipulation
改變DOM結(jié)構(gòu)的方法
.append(content,[content…])
在每個(gè)元素最后插入一個(gè)子元素
$('ul').append('<li class="plum">Plum</li>')$.html()//=> <ul id="fruits">// <li class="apple">Apple</li>// <li class="orange">Orange</li>// <li class="pear">Pear</li>// <li class="plum">Plum</li>// </ul>
.prepend(content,[content,…])
在每個(gè)元素最前插入一個(gè)子元素
$('ul').prepend('<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>
.after(content,[content,…])
在每個(gè)匹配元素之后插入一個(gè)元素
$('.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,…])
在每個(gè)匹配的元素之前插入一個(gè)元素
$('.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] )
從DOM中去除匹配的元素和它們的子元素。選擇器用來(lái)篩選要?jiǎng)h除的元素。
$('.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()
清空一個(gè)元素,移除所有的子元素
$('ul').empty()$.html()//=> <ul id="fruits"></ul>
.html( [htmlString] )
獲得元素的HTML字符串。如果htmlString有內(nèi)容的話,將會(huì)替代原來(lái)的HTML
$('.orange').html()//=> Orange$('#fruits').html('<li class="mango">Mango</li>').html()//=> <li class="mango">Mango</li>
.text( [textString] )
獲得元素的text內(nèi)容,包括子元素。如果textString被指定的話,每個(gè)元素的text內(nèi)容都會(huì)被替換。
$('.orange').text()//=> Orange$('ul').text()//=> Apple// Orange// Pear
Rendering
如果你想呈送document,你能使用html多效用函數(shù)。
$.html()//=> <ul id="fruits">// <li class="apple">Apple</li>// <li class="orange">Orange</li>// <li class="pear">Pear</li>// </ul>
如果你想呈送outerHTML,你可以使用 $.html(selector)
$.html('.pear')//=> <li class="pear">Pear</li>
默認(rèn)的,html會(huì)讓一些標(biāo)簽保持開標(biāo)簽的狀態(tài).有時(shí)候你想呈現(xiàn)一個(gè)有效的XML文檔.例如下面這個(gè):
$ = cheerio.load('<media:thumbnail url="http://www.foo.com/keyframe.jpg" width="75" height="50" time="12:05:01.123"/>');
然后為了呈現(xiàn)這個(gè)XML,你需要使用xml
這個(gè)函數(shù):
$.xml()//=> <media:thumbnail url="http://www.foo.com/keyframe.jpg" width="75" height="50" time="12:05:01.123"/>
Miscellaneous
不屬于其它地方的DOM 元素方法
.toArray()
取得所有的在DOM元素,轉(zhuǎn)化為數(shù)組、
$('li').toArray()//=> [ {...}, {...}, {...} ]
.clone()
克隆cheerio對(duì)象
var moreFruit = $('#fruits').clone()
Utilities
$.root有時(shí)候你想找到最上層的root元素,那么$.root()
就能獲得:
$.root().append('<ul id="vegetables"></ul>').html();//=> <ul id="fruits">...</ul><ul id="vegetables"></ul>
$.contains( container, contained )
查看cotained元素是否是container元素的子元素
$.parseHTML( data [, context ] [, keepScripts ] )
將字符串解析為DOM節(jié)點(diǎn)數(shù)組。context參數(shù)對(duì)chreeio沒有意義,但是用來(lái)維護(hù)APi的兼容性。
Screencasts
http://vimeo.com/31950192
這個(gè)視頻教程是follow-up Nettut的"How to Scrape Web Pages with Node.js and jQuery",用 cheerio而不是JSDOM+JQuery. 這個(gè)視頻就是展示chreeio多牛B,多快的。