轉(zhuǎn)載自http://cnodejs.org/topic/5203a71844e76d216a727d2e 焰枢,略加美化拱雏,以下正文。
所謂工欲善其事悬包,必先利其器,所以通讀了cheerio的API馍乙,順便翻譯了一遍,有些地方因為知道的比較少垫释,不知道什么意思丝格,保留了英文,希望各位不吝告訴我棵譬,然后一起把這個翻譯完成显蝌。
cheerio
為服務(wù)器特別定制的,快速、靈活曼尊、實施的jQuery核心實現(xiàn).
Introduction
將HTML告訴你的服務(wù)器
var cheerio = require('cheerio'), $ = cheerio.load('<h2 class="title">Hello world</h2>');
$('h2.title').text('Hello there!');
$('h2').addClass('welcome');
$.html();
//=> <h2 class="title welcome">Hello there!</h2>
Installationnpm install cheerio
Features
? 相似的語法:Cheerio 包括了 jQuery 核心的子集酬诀。Cheerio 從jQuery庫中去除了所有 DOM不一致性和瀏覽器尷尬的部分,揭示了它真正優(yōu)雅的API骆撇。
? 閃電般的塊:Cheerio 工作在一個非常簡單瞒御,一致的DOM模型之上。解析神郊,操作肴裙,呈送都變得難以置信的高效∮咳椋基礎(chǔ)的端到端的基準(zhǔn)測試顯示Cheerio 大約比JSDOM快八倍(8x)蜻懦。
? 巨靈活: Cheerio 封裝了兼容的htmlparser。Cheerio 幾乎能夠解析任何的 HTML 和 XML document夕晓。
What about JSDOM
我寫cheerio 是因為我發(fā)現(xiàn)我自己對JSDOM越來越沮喪宛乃。對于我來說,總是會一次又一次的碰上幾個難點蒸辆。
JSDOM內(nèi)建的解析太過于嚴(yán)格: JSDOM附帶的HTML解析不能處理很多當(dāng)下的大眾的網(wǎng)站征炼。
JSDOM太慢:用JSDOM解析大型網(wǎng)站存在可見的延遲。
JSDOM太累贅:JSDOM的目標(biāo)是提供一個我們在瀏覽器里面看到的相同的 DOM 環(huán)境吁朦。我從沒有真的需要所有這些東西柒室,我只是想要一個簡單的,相似的方法去處理HTML逗宜。
When I would use JSDOMCheerio
不會解決你的所有問題雄右。我人會使用JSDOM如果我需要用一個在服務(wù)器上的瀏覽器環(huán)境,特別是如果我想要自動化一些功能測試纺讲。
API
我們將用到的標(biāo)記示例
<ul id=“fruits”>
<li class=“apple”>Apple</li>
<li class=“orange”>Orange</li>
<li class=“pear”>Pear</li>
</ul>
這是我們將會在所有的API例子中用到的HTML標(biāo)記
Loading
首先你需要加載HTML擂仍。這一步對jQuery來說是必須的,since jQuery operates on the one, baked-in DOM熬甚。通過Cheerio,我們需要把HTML document 傳進(jìn)去逢渔。
這是首選:
var cheerio = require('cheerio'), $ = cheerio.load('<ul id="fruits">...</ul>');
或者通過傳遞字符串作為內(nèi)容來加載HTML:
$ = require('cheerio');$('ul', '<ul id="fruits">...</ul>');
Or as the root:
$ = require('cheerio');$('li', 'ul', '<ul id="fruits">...</ul>');
你也可以傳遞一個額外的對象給.load()如果你需要更改任何的默認(rèn)解析選項的話:
$ = cheerio.load('<ul id="fruits">...</ul>', { ignoreWhitespace: true, xmlMode: true});
這些解析選項都是直接來自htmlparser ,因此任何在htmlparser里有效的選項在Chreeio里也是行得通的乡括。默認(rèn)的選項如下:
{ ignoreWhitespace: false, xmlMode: false, lowerCaseTags: false}
想看選項清單和它們都效果肃廓,看DomHandler和Parser-options
Selectors
Cheerio的選擇器用起來幾乎和jQuery一樣,所以API也很相似诲泌。
$(selectior,[context],[root])
選擇器在 Context 范圍內(nèi)搜索盲赊,Context又在Root范圍內(nèi)搜索。selector 和context可是是一個字符串表達(dá)式敷扫,DOM元素哀蘑,和DOM元素的數(shù)組,或者chreeio對象。root 是通常是HTML 文檔字符串绘迁。
$('.apple', '#fruits').text()
//=> Apple$('ul .pear').attr('class')
//=> pear$('li[class=orange]').html()
//=> <li class="orange">Orange</li>
Attributes獲得和修改屬性
.attr(name,value)
獲得和修改屬性合溺。在匹配的元素中只能獲得第一元素的屬性。如果設(shè)置一個屬性的值為null缀台,則移除這個屬性棠赛。你也可以傳遞一對鍵值,或者一個函數(shù)将硝。
$('ul').attr('id')
//=> fruits
$('.apple').attr('id', 'favorite').html()
//=> <li class="apple" id="favorite">Apple</li>
更多信息請看這里
.value([value])
獲得和修改input,select,textarea的value.注意: 對于傳遞鍵值和函數(shù)的支持還沒有被加進(jìn)去恭朗。
$('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里去除一個或多個有空格分開的class依疼。如果className 沒有定義痰腮,所有的classes將會被去除,也可以傳函數(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)
獲得一個在匹配的元素中由選擇器濾過的后代。
$('#fruits').find('li').length
//=> 3
.parent([selector])
獲得每個匹配元素的parent,可選擇性的通過selector篩選巾钉。
$('.pear').parent().attr('id')
//=> fruits
.parents([selector])
獲得通過選擇器篩選匹配的元素的parent集合翘狱。
$('.orange').parents().length
// => 2
$('.orange').parents('#fruits').length
// => 1
.closest([selector])
對于每個集合內(nèi)的元素,通過測試這個元素和DOM層級關(guān)系上的祖先元素砰苍,獲得第一個匹配的元素
$('.orange').closest()
// => []
$('.orange').closest('.apple')
// => []
$('.orange').closest('li')
// => [<li class="orange">Orange</li>]
$('.orange').closest('#fruits')
// => [<ul id="fruits"> ... </ul>]
.next()
獲得第一個本元素之后的同級元素
$('.apple').next().hasClass('orange')
//=> true
.nextAll()
獲得本元素之后的所有同級元素
$('.apple').nextAll()
//=> [<li class="orange">Orange</li>, <li class="pear">Pear</li>]
.prev()
獲得本元素之前的第一個同級元素
$('.orange').prev().hasClass('apple')
//=> true
.preAll()
獲得本元素前的所有同級元素
$('.pear').prevAll()
//=> [<li class="orange">Orange</li>, <li class="apple">Apple</li>]
.slice(start,[end])
獲得選定范圍內(nèi)的元素
$('li').slice(1).eq(0).text()
//=> 'Orange'
$('li').slice(1, 2).length
//=> 1
.siblings(selector)
獲得被選擇的同級元素潦匈,除去自己??
$('.pear').siblings().length
//=> 2
$('.pear').siblings('.orange').length
//=> 1
.children(selector)
獲被選擇元素的子元素
$('#fruits').children().length
//=> 3
$('#fruits').children('.pear').text()
//=> Pear
.each(function(index,element))
迭代一個cheerio對象,為每個匹配元素執(zhí)行一個函數(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))
迭代一個cheerio對象,為每個匹配元素執(zhí)行一個函數(shù)吼旧。Map會返回一個迭代結(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))
迭代一個cheerio對象,濾出匹配選擇器或者是傳進(jìn)去的函數(shù)的元素圈暗。如果使用函數(shù)方法掂为,這個函數(shù)在被選擇的元素中執(zhí)行,所以this指向的手勢當(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()
會選擇chreeio對象的第一個元素
$('#fruits').children().first().text()
//=> Apple
.last()
會選擇chreeio對象的最后一個元素
$('#fruits').children().last().text()
//=> Pear
.eq(i)
通過索引篩選匹配的元素菩掏。使用.eq(-i)就從最后一個元素向前數(shù)。
$('li').eq(0).text()
//=> Apple
$('li').eq(-1).text()
//=> Pear
Manipulation
改變DOM結(jié)構(gòu)的方法
.append(content,[content…])
在每個元素最后插入一個子元素
$('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,…])
在每個元素最前插入一個子元素
$('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,…])
在每個匹配元素之后插入一個元素
$('.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] )
從DOM中去除匹配的元素和它們的子元素昵济。選擇器用來篩選要刪除的元素。
$('.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] )
獲得元素的HTML字符串访忿。如果htmlString有內(nèi)容的話瞧栗,將會替代原來的HTML
$('.orange').html()
//=> Orange
$('#fruits').html('<li class="mango">Mango</li>').html()
//=> <li class="mango">Mango</li>
.text( [textString] )
獲得元素的text內(nèi)容,包括子元素聂儒。如果textString被指定的話官册,每個元素的text內(nèi)容都會被替換批什。
$('.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會讓一些標(biāo)簽保持開標(biāo)簽的狀態(tài).有時候你想呈現(xiàn)一個有效的XML文檔.例如下面這個:
$ = cheerio.load('<media:thumbnail url="http://www.foo.com/keyframe.jpg" width="75" height="50" time="12:05:01.123"/>');
然后為了呈現(xiàn)這個XML,你需要使用xml
這個函數(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對象
var moreFruit = $('#fruits').clone()
Utilities
$.root
有時候你想找到最上層的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é)點數(shù)組珍语。context參數(shù)對chreeio沒有意義锤岸,但是用來維護(hù)APi的兼容性。
Screencasts
http://vimeo.com/31950192
這個視頻教程是follow-up Nettut的"How to Scrape Web Pages with Node.js and jQuery"板乙,用 cheerio而不是JSDOM+JQuery. 這個視頻就是展示chreeio多牛B是偷,多快的。