# Cheerio 教程

> 原文： [http://zetcode.com/javascript/cheerio/](http://zetcode.com/javascript/cheerio/)

Cheerio 教程展示了如何使用 Cheerio 模块在 JavaScript 中进行网页抓取。 Cheerio 实现了为服务器设计的 jQuery 的核心。

## Cheerio

Cheerio 是专门为服务器设计的核心 jQuery 的快速，灵活和精益实现。

在本教程中，我们从本地 Web 服务器上抓取 HTML。 对于本地 Web 服务器，我们使用`local-web-server`。

`index.html`

```js
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Home page</title>
    <style>
        .fpar {
            font-family: Georgia;
        }
    </style>
</head>

<body>
    <main>
        <h1>My website</h1>

        <p class="fpar">
            I am a JavaScript programmer.
        </p>

        <p>
            My hobbies are:
        </p>

        <ul>
            <li>Swimming</li>
            <li>Tai Chi</li>
            <li>Running</li>
            <li>Web development</li>
            <li>Reading</li>
            <li>Music</li>
        </ul>
    </main>
</body>

</html>

```

我们将使用此 HTML 文件。

## Cheerio 选择器

在 Cherrion 中，我们使用选择器来选择 HTML 文档的标签。 选择器语法是从 jQuery 借用的。

以下是可用选择器的部分列表：

*   `$("*")` - 选择所有元素
*   `$("#first")` — 用`id="first`选择元素
*   `$(".intro")` — 选择带有`class="intro"`的所有元素
*   `$("div")` - 选择所有`<div>`元素
*   `$("h2, div, p")` - 选择所有`<h2>, <div>, <p>`元素
*   `$("li:first")` — 选择第一个`<li>`元素
*   `$("li:last")` — 选择最后一个`<li>`元素
*   `$("li:even")` — 选择所有偶数`<li>`元素
*   `$("li:odd")` - 选择所有奇数`<li>`元素
*   `$(":empty")` - 选择所有为空的元素
*   `$(":focus")` - 选择当前具有焦点的元素

## 安装 Cheerio 和其他模块

我们安装了`cheerio`模块和两个附加模块。

```js
$ nodejs -v
v9.11.2

```

我们使用 Node 版本 9.11.2。

```js
$ sudo npm i cheerio
$ sudo npm i request
$ sudo npm i -g local-web-server

```

我们安装`cheerio`，`request`和`local-web-server`。

```js
$ ws
Serving at http://t400:8000, http://127.0.0.1:8000, http://192.168.0.3:8000

```

在项目目录中，我们有`index.html`文件，我们启动了本地 Web 服务器。 它会自动在三个不同的位置提供`index.html`文件。

## Cheerio 标题

在第一个示例中，我们获得了文档的标题。

`get_title.js`

```js
const cheerio = require('cheerio');
const request = require('request');

request({
    method: 'GET',
    url: 'http://localhost:8000'
}, (err, res, body) => {

    if (err) return console.error(err);

    let $ = cheerio.load(body);

    let title = $('title');

    console.log(title.text());
});

```

该示例打印 HTML 文档的标题。

```js
const cheerio = require('cheerio');
const request = require('request');

```

我们包括`cheerio`和`request`模块。 使用`cheerio`，我们可以进行网页抓取。 使用`request`，我们创建 GET 请求。

```js
request({
    method: 'GET',
    url: 'http://localhost:8000'
}, (err, res, body) => {

```

我们向本地 Web 服务器提供的 localhost 创建 GET 请求。 该资源在`body`参数中可用。

```js
let $ = cheerio.load(body);

```

首先，我们加载 HTML 文档。 为了模仿 jQuery，我们使用`$`变量。

```js
let title = $('title');

```

选择器返回`title`标签。

```js
console.log(title.text());

```

使用`text()`方法，我们获得`title`标签的文本。

```js
$ node get_title.js 
Home page

```

该示例打印文档的标题。

## Cheerio 获取父元素

使用`parent()`检索父元素。

`get_parent.js`

```js
const cheerio = require('cheerio');
const request = require('request');

request({
    method: 'GET',
    url: 'http://localhost:8000'
}, (err, res, body) => {

    if (err) return console.error(err);

    let $ = cheerio.load(body);

    let h1El = $('h1');

    let parentEl = h1El.parent();

    console.log(parentEl.get(0).tagName)
});

```

我们得到`h1`元素的父元素。

```js
$ node get_parent.js 
main

```

`h1`的父元素是`main`。

## Cheerio 第一个&最后一个元素

`cheerio`对象的第一个元素可以使用`first()`找到，最后一个元素可以使用`last()`找到。

`first_last.js`

```js
const cheerio = require('cheerio');
const request = require('request');

request({
    method: 'GET',
    url: 'http://localhost:8000'
}, (err, res, body) => {

    if (err) return console.error(err);

    let $ = cheerio.load(body);

    let main = $('main');

    let fel = main.children().first();
    let lel = main.children().last();

    console.log(fel.get(0).tagName);
    console.log(lel.get(0).tagName);
});

```

该示例打印`main`标签的第一个和最后一个元素。

```js
let main = $('main');

```

我们选择`main`标签。

```js
let fel = main.children().first();
let lel = main.children().last();

```

我们从`main`子级中获得第一个和最后一个元素。

```js
console.log(fel.get(0).tagName);
console.log(lel.get(0).tagName);

```

我们找出标签名称。

```js
$ node first_last.js 
h1
ul

```

`main`的第一个标签是`h1`，最后一个标签是`ul`。

## Cheerio 添加元素

`append()`方法在指定标签的末尾添加一个新元素。

`add_element.js`

```js
const cheerio = require('cheerio');
const request = require('request');

request({
    method: 'GET',
    url: 'http://localhost:8000'
}, (err, res, body) => {

    if (err) return console.error(err);

    let $ = cheerio.load(body);

    let ulEl = $('ul');

    ulEl.append('<li>Travel</li>');

    let lis = $('ul').html();
    let items = lis.split('\n');

    items.forEach((e) => {
        if (e) {
            console.log(e.replace(/(\s+)/g, ''));
        }
    });
});

```

在示例中，我们向`ul`元素添加了一个新列表项，并将其打印到控制台。

```js
ulEl.append('<li>Travel</li>');

```

我们增加了一个新的爱好。

```js
let lis = $('ul').html();

```

我们得到`ul`标签的 HTML。

```js
let items = lis.split('\n');

items.forEach((e) => {
    if (e) {
        console.log(e.replace(/(\s+)/g, ''));
    }
});

```

我们去除空格。 元素的文本数据包含大量空间。

```js
$ node add_element.js 
<li>Swimming</li>
<li>TaiChi</li>
<li>Running</li>
<li>Webdevelopment</li>
<li>Reading</li>
<li>Music</li>
<li>Travel</li>

```

在列表的末尾附加了一个新的旅行爱好。

## Cheerio 元素后插入

使用`after()`，我们可以在标签后插入元素。

`insert_after.js`

```js
const cheerio = require('cheerio');
const request = require('request');

request({
    method: 'GET',
    url: 'http://localhost:8000'
}, (err, res, body) => {

    if (err) return console.error(err);

    let $ = cheerio.load(body);

    $('main').after('<footer>This is a footer</footer>')

    console.log($.html());
});

```

在示例中，我们在`main`元素之后插入一个`footer`元素。

## Cheerio 在元素上循环

使用`each()`，我们可以循环遍历元素。

`loop_elements.js`

```js
const cheerio = require('cheerio');
const request = require('request');

request({
    method: 'GET',
    url: 'http://localhost:8000'
}, (err, res, body) => {

    if (err) return console.error(err);

    let $ = cheerio.load(body);

    let hobbies = [];

    $('li').each(function (i, e) {
        hobbies[i] = $(this).text();
    });

    console.log(hobbies);
});

```

该示例循环访问`ul`的`li`标签，并打印数组中元素的文本。

```js
$ node loop_elements.js 
[ 'Swimming',
  'Tai Chi',
  'Running',
  'Web development',
  'Reading',
  'Music' ]

```

这是输出。

## Cheerio 获取元素属性

可以使用`attr()`函数检索属性。

`attributes.js`

```js
const cheerio = require('cheerio');
const request = require('request');

request({
    method: 'GET',
    url: 'http://localhost:8000'
}, (err, res, body) => {

    if (err) return console.error(err);

    let $ = cheerio.load(body);

    let fpEl = $('h1 + p');
    let attrs = fpEl.attr();

    console.log(attrs);
});

```

在示例中，我们获得了`h1`的直接同级段落的属性。

```js
$ node attributes.js 
{ class: 'fpar' }

```

该段包含`fpar`类。

## Cheerio 过滤器

我们可以使用`filter()`在元素上应用过滤器。

`filtering.js`

```js
const cheerio = require('cheerio');
const request = require('request');

request({
    method: 'GET',
    url: 'http://localhost:8000'
}, (err, res, body) => {

    if (err) return console.error(err);

    let $ = cheerio.load(body);

    let allEls = $('*');

    let filteredEls = allEls.filter(function (i, el) {
        // this === el
        return $(this).children().length > 3;
    });

    let items = filteredEls.get();

    items.forEach(e => {
        console.log(e.name);
    });

});

```

在示例中，我们找到了包含三个以上子元素的文档的所有元素。

```js
let allEls = $('*');

```

`*`选择器选择所有元素。

```js
let filteredEls = allEls.filter(function (i, el) {
    // this === el
    return $(this).children().length > 3;
});

```

在检索到的元素上，我们应用过滤器。 仅当元素包含三个以上的子元素时，该元素才包含在过滤列表中。

```js
let items = filteredEls.get();

items.forEach(e => {
    console.log(e.name);
});

```

我们遍历过滤后的列表并打印元素的名称。

```js
$ node filtering.js 
head
main
ul

```

`head`，`main`和`ul`元素包含三个以上的子代。 不包含`body`，因为它仅包含一个直属子代。

在本教程中，我们使用 Cheerio 库在 JavaScript 中完成了 Web 抓取。

您可能也对以下相关教程感兴趣： [JQuery 教程](/web/jquery/)， [Moment.js 教程](/javascript/momentjs/)，[从 JavaScript 中的 URL 读取 JSON](/articles/javascriptjsonurl/) ， [JavaScript 贪食蛇教程](/javascript/snake/) ， [Node Sass 教程](/javascript/nodesass/)， [Lodash 教程](/javascript/lodash/)。