1
2
3
4
5
6
7
8
const cheerio = require('cheerio')
const $ = cheerio.load('<h2 class="title">Hello world</h2>')

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

$.html()
//=> <html><head></head><body><h2 class="title welcome">Hello there!</h2></body></html>

安装

1
npm install cheerio

特性

❤ 熟悉的语法:
Cheerio 实现了 jQuery 核心 的一个子集。Cheerio 从 jQuery 库中,删除了所有 DOM 和浏览器不一致的残骸,揭示了它真正华丽的 API。

ϟ 非常快:
Cheerio 使用非常简单,一致的 DOM 模型。因此,解析,操纵和渲染非常有效。初步的端到端基准测试表明,cheerio 是8x快于 JSDOM 。

❁ 非常灵活:
Cheerio wraps around parse5 parser and can optionally use @FB55’s forgiving htmlparser2。Cheerio 几乎可以解析,任何 HTML 或 XML 文档。

Cheerio 不是 Web 浏览器

Cheerio 解析(html)标记,并提供用于遍历/操纵,结果数据结构的 API。它不会像 Web 浏览器那样解释结果。具体来说,并不会生成可视化渲染,应用 CSS,加载外部资源或执行 JavaScript。如果您的用例,需要任何此功能,您应该考虑像其他项目:PhantomJSJSDom

API

我们将会用到的代码示例:

1
2
3
4
5
<ul id="fruits">
<li class="apple">Apple</li>
<li class="orange">Orange</li>
<li class="pear">Pear</li>
</ul>

这里的 HTML 标记,是我们所有 API 示例的。

加载

首先,您需要加载 HTML。jQuery 中的这一步是隐含的,因为 jQuery 在一个烤着的 DOM 上运行的。而 Cheerio,我们是需要传递 HTML 文档给它。

这是首选方法:

1
2
const cheerio = require('cheerio');
const $ = cheerio.load('<ul id="fruits">...</ul>');

或者,您也可以通过,将字符串作为上下文传递,来加载 HTML:

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

或者直接选择li元素:

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

.load()还可以传递一个额外的对象,如果您需要修改任何默认解析选项的话:

1
2
3
4
5
const $ = cheerio.load('<ul id="fruits">...</ul>', {
xml: {
normalizeWhitespace: true,
}
});

这些解析选项,直接来自htmlparser2,因此,任何htmlparser2可用的选项,在 cheerio 中也有效。默认选项是:

1
2
3
4
5
6
{
withDomLvl1: true,
normalizeWhitespace: false,
xmlMode: true,
decodeEntities: true
}

有关选项及其效果的完整列表,请参阅这里htmlparser2 的选项

Some users may wish to parse markup with the htmlparser2 library, and
traverse/manipulate the resulting structure with Cheerio. This may be the case
for those upgrading from pre-1.0 releases of Cheerio (which relied on
htmlparser2), for those dealing with invalid markup (because htmlparser2 is
more forgiving), or for those operating in performance-critical situations
(because htmlparser2 may be faster in some cases). Note that “more forgiving”
means htmlparser2 has error-correcting mechanisms that aren’t always a match
for the standards observed by web browsers. This behavior may be useful when
parsing non-HTML content.

To support these cases, load also accepts a htmlparser2-compatible data
structure as its first argument. Users may install htmlparser2, use it to
parse input, and pass the result to load:

1
2
3
4
5
// Usage as of htmlparser2 version 3:
const htmlparser2 = require('htmlparser2');
const dom = htmlparser2.parseDOM(document, options);

const $ = cheerio.load(dom);

选择器

Cheerio 的选择器实现,几乎与 jQuery 相同,因此 API 非常相似。

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

selector,会搜索context范围,而该范围又是从root范围搜索而来。selectorcontext可以是字符串表达式,DOM 元素,DOM 元素数组或 cheerio 对象。root通常是 HTML 文档字符串。

此选择器方法是遍历和操纵文档的起点。像 jQuery 一样,它是在文档中,选择元素的主要方法,但与 jQuery 不同,我们是构建在 CSSSelect 库之上的,CSSSelect 实现了大多数的 Sizzle 选择器。

1
2
3
4
5
6
7
8
$('.apple', '#fruits').text()
//=> Apple

$('ul .pear').attr('class')
//=> pear

$('li[class=orange]').html()
//=> Orange
XML Namespaces

您可以选择 XML 命名空间,但是遵循 CSS 规范,冒号(:)需要进行转义,才能使选择器有效。

1
$('[xml\\:id="main"');

渲染

When you’re ready to render the document, you can call the html method on the “root” selection:

1
2
3
4
5
6
7
8
9
10
11
$.root().html()
//=> <html>
// <head></head>
// <body>
// <ul id="fruits">
// <li class="apple">Apple</li>
// <li class="orange">Orange</li>
// <li class="pear">Pear</li>
// </ul>
// </body>
// </html>

If you want to render the outerHTML of a selection, you can use the html utility functon:

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

By default, html will leave some tags open. Sometimes you may instead want to render a valid XML document. For example, you might parse the following XML snippet:

1
const $ = cheerio.load('<media:thumbnail url="http://www.foo.com/keyframe.jpg" width="75" height="50" time="12:05:01.123"/>');

… and later want to render to XML. To do this, you can use the ‘xml’ utility function:

1
2
$.xml()
//=> <media:thumbnail url="http://www.foo.com/keyframe.jpg" width="75" height="50" time="12:05:01.123"/>

You may also render the text content of a Cheerio object using the text static method:

1
2
3
const $ = cheerio.load('This is <em>content</em>.')
cheerio.text($('body'))
//=> This is content.

插件

一旦加载文档后,您可以扩展原型,或等效fn属性,使用自定义插件方法:

1
2
3
4
5
6
const $ = cheerio.load('<html><body>Hello, <b>world</b>!</body></html>');
$.prototype.logHtml = function() {
console.log(this.html());
};

$('body').logHtml(); // logs "Hello, <b>world</b>!" to the console

“DOM Node” 对象

Cheerio 所制造的对象,与基于浏览器的 DOM 节点有许多相似之处。所以,您可以期望它们定义了以下属性:

  • tagName
  • parentNode
  • previousSibling
  • nextSibling
  • nodeValue
  • firstChild
  • childNodes
  • lastChild

Screencasts

http://vimeo.com/31950192

这个视频教程是 Nettut 的“如何使用 Node.js 和 jQuery 抓取网页”的后续内容,使用 cheerio 而不是 JSDOM + jQuery。这个视频展示了使用 cheerio 是多么容易,以及 cheerio 比 JSDOM + jQuery 快多少。

测试

要运行测试套件,请下载存储库,然后在 cheerio 目录中,运行:

1
2
make setup
make test

这将下载开发包,并运行测试套件。