cheerio 筆記

艾倫先生發表於2017-12-14

簡介

cheerio是一個node的庫,可以理解為一個Node.js版本的jquery,用來從網頁中以 css selector取資料,使用方式和jquery基本相同。

npm install cheerio --save

var cheerio = require('cheerio')
var $ = 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不一致性和瀏覽器尷尬的部分,效能更優。

load 裝載DOM

首先你需要載入HTML。這一步對jQuery來說是必須的,通過Cheerio,我們需要把HTML document 傳進去,下面的程式碼都針對如下程式碼

var html = '<ul id="fruits"> <li class="apple">Apple</li> <li class="orange">Orange</li> <li class="pear">Pear</li> </ul>'
//DOM結構如下
<ul id="fruits">
  <li class="apple">Apple</li>
  <li class="orange">Orange</li>
  <li class="pear">Pear</li>
</ul>

var cheerio = require('cheerio'),
$ = cheerio.load(html);
複製程式碼

選擇器

$(selectior,[context],[root])
複製程式碼

選擇器在 Context 範圍內搜尋,Context又在Root範圍內搜尋。注意:這裡是root在右,context在左。selector 和context可以是一個字串表示式,DOM元素,和DOM元素的陣列,或者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元素
複製程式碼

### attr()修改屬性

attr(name,value)
複製程式碼

獲得和修改屬性。在匹配的元素中只能獲得第一元素的屬性。如果設定一個屬性的值為null,則移除這個屬性。你也可以傳遞一對鍵值,或者一個函式。

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

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

$('.apple').attr('class', 'favorite').html()
//=> <li class="favorite">Apple</li>
複製程式碼

removeAttr(name)

通過name刪除屬性 $('.pear').removeAttr('class').html() //=> pear

### prop()修改狀態值

$('input[type="checkbox"]').prop('checked')
//=> false

$('input[type="checkbox"]').prop('checked', true).val()
//=> ok
複製程式碼

data()自定義屬性

$('<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'
複製程式碼

val()賦值

$('input[type="text"]').val()
//=> input_text

$('input[type="text"]').val('test').html()
//=> <input type="text" value="test"/>
複製程式碼

hasClass( className )

檢查匹配的元素是否有給出的類名

$('.pear').hasClass('pear')//=> true
$('apple').hasClass('fruit')//=> false
$('li').hasClass('pear')//=> true
複製程式碼

addClass(name)

增加class(es)給所有匹配的elements.也可以傳函式。

$('.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將會被去除,也可以傳函式

$('.pear').removeClass('pear').html()//=>Pear
$('.apple').addClass('red').removeClass().html()//=>Apple
複製程式碼

查詢語法

find(selector)

獲得一個在匹配的元素中由選擇器濾過的後代

$('#fruits').find('li').length//=> 3
複製程式碼

parent([selector])

獲得通過選擇器篩選匹配的元素的parent集合

$('.orange').parents().length// => 2
$('.orange').parents('#fruits').length// => 1
複製程式碼

next()獲得第一個本元素之後的同級元素

$('.apple').next().hasClass('orange')//=> true
$('.pear').next().html()//=> null
複製程式碼

.nextAll()

獲得本元素之後的所有同級元素 $('.apple').nextAll()//=> [

  • Orange
  • ,
  • Pear
  • ]
    $('.apple').nextAll().length//=>2

    ###prev() 獲得本元素之前的第一個同級元素 $('.orange').prev().hasClass('apple')//=> true

    preAll()

    獲得本元素前的所有同級元素 $('.pear').prevAll()//=> [

  • Orange
  • ,
  • Apple
  • ]

    ### slice(start,[end]) 獲得選定範圍內的元素陣列 $('li').slice(1).eq(0).text()//=> 'Orange' $('li').slice(1, 2).length//=> 1

    siblings(selector)

    獲得被選擇的同級元素(除去自己) $('.pear').siblings().length//=> 2 $('.pear').siblings('.orange').length//=> 1 $('.pear').siblings('.pear').length//=> 0

    first()

    會選擇chreeio物件的第一個元素 ('#fruits').children().first().text()//=> Apple

    last()

    會選擇chreeio物件的最後一個元素 $('#fruits').children().last().text()//=> Pear

    eq(i)

    通過索引篩選匹配的元素。使用.eq(-i)就從最後一個元素向前數。 $('li').eq(0).text()//=> Apple $('li').eq(-1).text()//=> Pear

    children(selector)

    獲被選擇元素的子元素 $('#fruits').children().length//=> 3 $('#fruits').children('.pear').text()//=> Pear

    each(function(index,element))

    迭代一個cheerio物件,為每個匹配元素執行一個函式。要提早跳出迴圈,返回false.

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

    map(function(index,element))

    迭代一個cheerio物件,為每個匹配元素執行一個函式。Map會返回一個迭代結果的陣列。

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

    filter(selector)

    迭代一個cheerio物件,濾出匹配選擇器或者是傳進去的函式的元素。如果使用函式方法,這個函式在被選擇的元素中執行,所以this指向的手勢當前元素。

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

    改變DOM結構的方法

    append(content,[content…])

    在每個元素最後插入一個子元素

    $('ul').append('<li class="plum">Plum</li>')
    $.html()
    //=>
    // <li class="apple">Apple</li>
    // <li class="orange">Orange</li>
    // <li class="pear">Pear</li>
    // <li class="plum">Plum</li>//
    複製程式碼

    prepend(content,[content,…])

    在每個元素最前插入一個子元素

    $('ul').prepend('<li class="plum">Plum</li>')
    $.html()
    //=>
    // <li class="plum">Plum</li>
    // <li class="apple">Apple</li>
    // <li class="orange">Orange</li>
    // <li class="pear">Pear</li>
    複製程式碼

    after(content,[content,…])

    在每個匹配元素之後插入一個元素

    $('.apple').after('<li class="plum">Plum</li>')
    $.html()
    //=>
    // <li class="apple">Apple</li>
    // <li class="plum">Plum</li>
    // <li class="orange">Orange</li>
    // <li class="pear">Pear</li>
    複製程式碼

    before(content,[content,…])

    在每個匹配的元素之前插入一個元素

    $('.apple').before('<li class="plum">Plum</li>')
    $.html()
    //=>
    // <li class="plum">Plum</li>
    // <li class="apple">Apple</li>
    // <li class="orange">Orange</li>
    // <li class="pear">Pear</li>
    複製程式碼

    remove( [selector] )

    從DOM中去除匹配的元素和它們的子元素。選擇器用來篩選要刪除的元素。

    $('.pear').remove()
    $.html()//=>
    
    // <li class="apple">Apple</li>
    // <li class="orange">Orange</li>
    複製程式碼

    replaceWith( content )

    替換匹配的的元素

    var plum = $('<li class="plum">Plum</li>')
    $('.pear').replaceWith(plum)
    $.html()
    //=>
    // <li class="apple">Apple</li>
    // <li class="orange">Orange</li>
    // <li class="plum">Plum</li>//
    複製程式碼

    empty()

    清空一個元素,移除所有的子元素

    $('ul').empty()$.html()
    複製程式碼

    html( [htmlString] )

    獲得元素的HTML字串。如果htmlString有內容的話,將會替代原來的HTML

    $('.orange').html()
    //=> Orange
    $('#fruits').html('<li class="mango">Mango</li>').html()
    //=> <li class="mango">Mango</li>
    複製程式碼

    text( [textString] )

    獲得元素的text內容,包括子元素。如果textString被指定的話,每個元素的text內容都會被替換。

    $('.orange').text()//=> Orange
    $('ul').text()//=> Apple// Orange// Pear
    複製程式碼

    cheerio 實踐

    下載類

    var http = require("http");
     
    function download(url, callback) {
      http.get(url, function(res) {
        var data = "";
        res.on('data', function (chunk) {
          data += chunk;
        });
        res.on("end", function() {
          callback(data);
        });
      }).on("error", function() {
        callback(null);
      });
    }
    
    exports.download = download;
    複製程式碼

    下載類的使用

    var cheerio = require("cheerio");
    var loadUrl = require("./loadUrl");
     
    var url = "http://www.example.com"
    
    loadUrl.download(url, function(data) {console.log(data);});
    複製程式碼