原文: http://zetcode.com/javascript/cheerio/

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

Cheerio

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

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

index.html

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <meta name="viewport" content="width=device-width, initial-scale=1.0">
  6. <meta http-equiv="X-UA-Compatible" content="ie=edge">
  7. <title>Home page</title>
  8. <style>
  9. .fpar {
  10. font-family: Georgia;
  11. }
  12. </style>
  13. </head>
  14. <body>
  15. <main>
  16. <h1>My website</h1>
  17. <p class="fpar">
  18. I am a JavaScript programmer.
  19. </p>
  20. <p>
  21. My hobbies are:
  22. </p>
  23. <ul>
  24. <li>Swimming</li>
  25. <li>Tai Chi</li>
  26. <li>Running</li>
  27. <li>Web development</li>
  28. <li>Reading</li>
  29. <li>Music</li>
  30. </ul>
  31. </main>
  32. </body>
  33. </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模块和两个附加模块。

  1. $ nodejs -v
  2. v9.11.2

我们使用 Node 版本 9.11.2。

  1. $ sudo npm i cheerio
  2. $ sudo npm i request
  3. $ sudo npm i -g local-web-server

我们安装cheeriorequestlocal-web-server

  1. $ ws
  2. 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

  1. const cheerio = require('cheerio');
  2. const request = require('request');
  3. request({
  4. method: 'GET',
  5. url: 'http://localhost:8000'
  6. }, (err, res, body) => {
  7. if (err) return console.error(err);
  8. let $ = cheerio.load(body);
  9. let title = $('title');
  10. console.log(title.text());
  11. });

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

  1. const cheerio = require('cheerio');
  2. const request = require('request');

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

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

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

  1. let $ = cheerio.load(body);

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

  1. let title = $('title');

选择器返回title标签。

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

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

  1. $ node get_title.js
  2. Home page

该示例打印文档的标题。

Cheerio 获取父元素

使用parent()检索父元素。

get_parent.js

  1. const cheerio = require('cheerio');
  2. const request = require('request');
  3. request({
  4. method: 'GET',
  5. url: 'http://localhost:8000'
  6. }, (err, res, body) => {
  7. if (err) return console.error(err);
  8. let $ = cheerio.load(body);
  9. let h1El = $('h1');
  10. let parentEl = h1El.parent();
  11. console.log(parentEl.get(0).tagName)
  12. });

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

  1. $ node get_parent.js
  2. main

h1的父元素是main

Cheerio 第一个&最后一个元素

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

first_last.js

  1. const cheerio = require('cheerio');
  2. const request = require('request');
  3. request({
  4. method: 'GET',
  5. url: 'http://localhost:8000'
  6. }, (err, res, body) => {
  7. if (err) return console.error(err);
  8. let $ = cheerio.load(body);
  9. let main = $('main');
  10. let fel = main.children().first();
  11. let lel = main.children().last();
  12. console.log(fel.get(0).tagName);
  13. console.log(lel.get(0).tagName);
  14. });

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

  1. let main = $('main');

我们选择main标签。

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

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

  1. console.log(fel.get(0).tagName);
  2. console.log(lel.get(0).tagName);

我们找出标签名称。

  1. $ node first_last.js
  2. h1
  3. ul

main的第一个标签是h1,最后一个标签是ul

Cheerio 添加元素

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

add_element.js

  1. const cheerio = require('cheerio');
  2. const request = require('request');
  3. request({
  4. method: 'GET',
  5. url: 'http://localhost:8000'
  6. }, (err, res, body) => {
  7. if (err) return console.error(err);
  8. let $ = cheerio.load(body);
  9. let ulEl = $('ul');
  10. ulEl.append('<li>Travel</li>');
  11. let lis = $('ul').html();
  12. let items = lis.split('\n');
  13. items.forEach((e) => {
  14. if (e) {
  15. console.log(e.replace(/(\s+)/g, ''));
  16. }
  17. });
  18. });

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

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

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

  1. let lis = $('ul').html();

我们得到ul标签的 HTML。

  1. let items = lis.split('\n');
  2. items.forEach((e) => {
  3. if (e) {
  4. console.log(e.replace(/(\s+)/g, ''));
  5. }
  6. });

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

  1. $ node add_element.js
  2. <li>Swimming</li>
  3. <li>TaiChi</li>
  4. <li>Running</li>
  5. <li>Webdevelopment</li>
  6. <li>Reading</li>
  7. <li>Music</li>
  8. <li>Travel</li>

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

Cheerio 元素后插入

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

insert_after.js

  1. const cheerio = require('cheerio');
  2. const request = require('request');
  3. request({
  4. method: 'GET',
  5. url: 'http://localhost:8000'
  6. }, (err, res, body) => {
  7. if (err) return console.error(err);
  8. let $ = cheerio.load(body);
  9. $('main').after('<footer>This is a footer</footer>')
  10. console.log($.html());
  11. });

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

Cheerio 在元素上循环

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

loop_elements.js

  1. const cheerio = require('cheerio');
  2. const request = require('request');
  3. request({
  4. method: 'GET',
  5. url: 'http://localhost:8000'
  6. }, (err, res, body) => {
  7. if (err) return console.error(err);
  8. let $ = cheerio.load(body);
  9. let hobbies = [];
  10. $('li').each(function (i, e) {
  11. hobbies[i] = $(this).text();
  12. });
  13. console.log(hobbies);
  14. });

该示例循环访问ulli标签,并打印数组中元素的文本。

  1. $ node loop_elements.js
  2. [ 'Swimming',
  3. 'Tai Chi',
  4. 'Running',
  5. 'Web development',
  6. 'Reading',
  7. 'Music' ]

这是输出。

Cheerio 获取元素属性

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

attributes.js

  1. const cheerio = require('cheerio');
  2. const request = require('request');
  3. request({
  4. method: 'GET',
  5. url: 'http://localhost:8000'
  6. }, (err, res, body) => {
  7. if (err) return console.error(err);
  8. let $ = cheerio.load(body);
  9. let fpEl = $('h1 + p');
  10. let attrs = fpEl.attr();
  11. console.log(attrs);
  12. });

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

  1. $ node attributes.js
  2. { class: 'fpar' }

该段包含fpar类。

Cheerio 过滤器

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

filtering.js

  1. const cheerio = require('cheerio');
  2. const request = require('request');
  3. request({
  4. method: 'GET',
  5. url: 'http://localhost:8000'
  6. }, (err, res, body) => {
  7. if (err) return console.error(err);
  8. let $ = cheerio.load(body);
  9. let allEls = $('*');
  10. let filteredEls = allEls.filter(function (i, el) {
  11. // this === el
  12. return $(this).children().length > 3;
  13. });
  14. let items = filteredEls.get();
  15. items.forEach(e => {
  16. console.log(e.name);
  17. });
  18. });

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

  1. let allEls = $('*');

*选择器选择所有元素。

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

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

  1. let items = filteredEls.get();
  2. items.forEach(e => {
  3. console.log(e.name);
  4. });

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

  1. $ node filtering.js
  2. head
  3. main
  4. ul

headmainul元素包含三个以上的子代。 不包含body,因为它仅包含一个直属子代。

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

您可能也对以下相关教程感兴趣: JQuery 教程Moment.js 教程从 JavaScript 中的 URL 读取 JSONJavaScript 贪食蛇教程Node Sass 教程Lodash 教程