cheerio

cheerio是一個(gè)node的庫移必,可以理解為一個(gè)Node.js版本的jquery友鼻,用來從網(wǎng)頁中以 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>

特性

  • 相似的語法:Cheerio 包括了 jQuery 核心的子集。Cheerio 從jQuery庫中去除了所有 DOM不一致性和瀏覽器尷尬的部分娇跟,揭示了它真正優(yōu)雅的API岩齿。
  • 閃電般的塊:Cheerio 工作在一個(gè)非常簡單,一致的DOM模型之上苞俘。解析盹沈,操作,呈送都變得難以置信的高效吃谣∑蚍猓基礎(chǔ)的端到端的基準(zhǔn)測試顯示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锚贱。這一步對jQuery來說是必須的,通過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>');

你也可以傳遞一個(gè)額外的對象給.load()如果你需要更改任何的默認(rèn)解析選項(xiàng)的話:

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

這些解析選項(xiàng)都是直接來自htmlparser 拧廊,因此任何在htmlparser里有效的選項(xiàng)在Chreeio里也是行得通的。默認(rèn)的選項(xiàng)如下:

{
    withDomLvl1: true,
    normalizeWhitespace: false,
    xmlMode: false,
    decodeEntities: true
}

想看選項(xiàng)清單和它們都效果悍缠,看這個(gè)這個(gè)

Selectors

Cheerio的選擇器用起來幾乎和jQuery一樣卦绣,所以API也很相似。
$(selectior,[context],[root])
選擇器在 Context 范圍內(nèi)搜索飞蚓,Context又在Root范圍內(nèi)搜索滤港。注意:這里是root在右,context在左趴拧。selector 和context可以是一個(gè)字符串表達(dá)式溅漾,DOM元素,和DOM元素的數(shù)組著榴,或者chreeio對象添履。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è)屬性。你也可以傳遞一對鍵值严卖,或者一個(gè)函數(shù)席舍。

$('ul').attr('id')
//=> fruits

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

更多信息請看這里

.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])
對于每個(gè)集合內(nèi)的元素色查,通過測試這個(gè)元素和DOM層級關(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è)本元素之后的同級元素
$('.apple').next().hasClass('orange')//=> true

.nextAll()
獲得本元素之后的所有同級元素
$('.apple').nextAll()//=> [<li class="orange">Orange</li>, <li class="pear">Pear</li>]

.prev()
獲得本元素之前的第一個(gè)同級元素
$('.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))
迭代一個(gè)cheerio對象秧了,為每個(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對象验毡,為每個(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對象晶通,濾出匹配選擇器或者是傳進(jìn)去的函數(shù)的元素。如果使用函數(shù)方法哟玷,這個(gè)函數(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()
會(huì)選擇chreeio對象的第一個(gè)元素
$('#fruits').children().first().text()//=> Apple

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

會(huì)選擇chreeio對象的最后一個(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中去除匹配的元素和它們的子元素。選擇器用來篩選要?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ì)替代原來的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對象
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ù)對chreeio沒有意義,但是用來維護(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,多快的携茂。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末你踩,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌带膜,老刑警劉巖吩谦,帶你破解...
    沈念sama閱讀 211,123評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異膝藕,居然都是意外死亡式廷,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,031評論 2 384
  • 文/潘曉璐 我一進(jìn)店門芭挽,熙熙樓的掌柜王于貴愁眉苦臉地迎上來滑废,“玉大人,你說我怎么就攤上這事袜爪∪涑茫” “怎么了?”我有些...
    開封第一講書人閱讀 156,723評論 0 345
  • 文/不壞的土叔 我叫張陵辛馆,是天一觀的道長。 經(jīng)常有香客問我怀各,道長倔韭,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,357評論 1 283
  • 正文 為了忘掉前任瓢对,我火速辦了婚禮寿酌,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘硕蛹。我一直安慰自己醇疼,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,412評論 5 384
  • 文/花漫 我一把揭開白布法焰。 她就那樣靜靜地躺著秧荆,像睡著了一般。 火紅的嫁衣襯著肌膚如雪埃仪。 梳的紋絲不亂的頭發(fā)上乙濒,一...
    開封第一講書人閱讀 49,760評論 1 289
  • 那天,我揣著相機(jī)與錄音卵蛉,去河邊找鬼颁股。 笑死,一個(gè)胖子當(dāng)著我的面吹牛傻丝,可吹牛的內(nèi)容都是我干的甘有。 我是一名探鬼主播,決...
    沈念sama閱讀 38,904評論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼葡缰,長吁一口氣:“原來是場噩夢啊……” “哼亏掀!你這毒婦竟也來了忱反?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,672評論 0 266
  • 序言:老撾萬榮一對情侶失蹤滤愕,失蹤者是張志新(化名)和其女友劉穎温算,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體该互,經(jīng)...
    沈念sama閱讀 44,118評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡米者,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,456評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了宇智。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片蔓搞。...
    茶點(diǎn)故事閱讀 38,599評論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖随橘,靈堂內(nèi)的尸體忽然破棺而出喂分,到底是詐尸還是另有隱情,我是刑警寧澤机蔗,帶...
    沈念sama閱讀 34,264評論 4 328
  • 正文 年R本政府宣布蒲祈,位于F島的核電站,受9級特大地震影響萝嘁,放射性物質(zhì)發(fā)生泄漏梆掸。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,857評論 3 312
  • 文/蒙蒙 一牙言、第九天 我趴在偏房一處隱蔽的房頂上張望酸钦。 院中可真熱鬧,春花似錦咱枉、人聲如沸卑硫。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,731評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽欢伏。三九已至,卻和暖如春亿乳,著一層夾襖步出監(jiān)牢的瞬間硝拧,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,956評論 1 264
  • 我被黑心中介騙來泰國打工葛假, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留障陶,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,286評論 2 360
  • 正文 我出身青樓桐款,卻偏偏與公主長得像,于是被迫代替她去往敵國和親夷恍。 傳聞我的和親對象是個(gè)殘疾皇子魔眨,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,465評論 2 348

推薦閱讀更多精彩內(nèi)容