Node.js爬虫 CheerioJS ‌轻量级解析、操作和渲染HTML及XML文档

简介

‌ CheerioJS ‌ 是一个专为 Node.js 设计的轻量级库,用于解析、操作和渲染 HTML 及 XML 文档,语法类似 Jquery。

安装

复制代码
npm install cheerio

示例

复制代码
const cheerio = require("cheerio");

const html = `
<html>
  <head>
    <title>Example</title>
  </head>
  <body>
    <h1>Hello, world!</h1>
  </body>
</html>
`;

const $ = cheerio.load(html);

console.log($("h1").text()); // 输出: Hello, world!

加载文档

load

解析 HTML 或 XML 文档的最基本方式

复制代码
import * as cheerio from "cheerio";

const html = `
<html>
  <head>
    <title>Example</title>
  </head>
  <body>
    <div class="container">
      <div class="item">React.js</div>
      <div class="item">Vue.js</div>
      <div class="item">Angular.js</div>
    </div>
  </body>
</html>
`;

const $ = cheerio.load(html);
console.log(111, $("div.container .item:first-child").text()); // 输出: React.js

loadBuffer

解析存储文档内容的 buffer 类型数据结构

复制代码
import * as cheerio from "cheerio";
import * as fs from "fs";

const buffer = fs.readFileSync("document.html");
const $ = cheerio.loadBuffer(buffer);
console.log(111, $("div.container .item:first-child").text()); // 输出: React.js

fromURL

从 URL 加载文档

复制代码
import * as cheerio from "cheerio";

const $ = await cheerio.fromURL("https://example.com");

选择元素

Cheerio 允许用户使用 CSS 选择器 从文档中选择元素。方法语法与 jquery 基本一样。

复制代码
$("p"); // 选择所有 <p> 元素
$("p.item"); // 选择所有 class 为 item 的 <p> 元素
$("p.item:first-child"); // 选择第一个 class 为 item 的 <p> 元素
$("p.item:last-child"); // 选择最后一个 class 为 item 的 <p> 元素
$(".selected"); // 选择所有 class 为 selected 的元素
$("[data-selected=true]"); // 选择所有 data-selected 属性为 true 的元素
$('[xml\\:id="main"'); // 选择所有 xml:id 属性为 main 的元素
$("p.selected"); // 选择所有 class 为 selected 的 <p> 元素
$("div p"); // 选择所有 <div> 元素中的 <p> 元素
$("div > p"); // 选择所有直接子元素为 <p> 的 <div> 元素
$('p:contains("hello")'); // 选择所有包含 "hello" 文字的 <p> 元素

find 查找元素

复制代码
import * as cheerio from "cheerio";

const html = `
<html>
  <head>
    <title>Example</title>
  </head>
  <body>
    <div class="container">
      <div class="item">React.js</div>
      <div class="item">Vue.js</div>
      <div class="item">Angular.js</div>
    </div>
  </body>
</html>
`;

const $ = cheerio.load(html);
const items = $(".container").find(".item");
items.each((index, element) => {
  console.log($(element).text());
});

children 查找子元素

复制代码
import * as cheerio from "cheerio";

const html = `
<html>
  <head>
    <title>Example</title>
  </head>
  <body>
    <div class="container">
      <div class="item">React.js</div>
      <div class="item">Vue.js</div>
      <div class="item">Angular.js</div>
    </div>
  </body>
</html>
`;

const $ = cheerio.load(html);
const items = $(".container").children(".item");
items.each((index, element) => {
  console.log($(element).text());
});

find vs children 区别

  • find 方法会递归查找所有符合条件的元素,包括子元素、子元素的子元素等。
  • children 方法只会查找直接子元素,不会查找子元素的子元素。

contents 查找所有子节点

所有子元素,包括文本和注释节点。

复制代码
import * as cheerio from "cheerio";

const html = `
    <div class="container">
      <div class="item">1</div>
      <div class="item">2</div>
      <div class="item">3</div>
    </div>
    `;
const $ = cheerio.load(html);
const items = $(".container").contents();
console.log(items.length); // 输出: 7

parent 查找父元素

复制代码
import * as cheerio from "cheerio";

const html = `
    <div class="container">
      <div class="item">1</div>
      <div class="item">2</div>
      <div class="item">3</div>
    </div>
    `;
const $ = cheerio.load(html);
const parent = $(".item").parent();
console.log(parent.prop("class")); // 输出: container

parents 查找所有父元素

复制代码
import * as cheerio from "cheerio";

const html = `
    <div class="container">
      <div class="item">1</div>
      <div class="item">2</div>
      <div class="item">3</div>
    </div>
    `;
const $ = cheerio.load(html);
const parents = $(".item").parents();
parents.each((index, element) => {
  console.log($(element).prop("tagName"));
});
// 输出:DIV、BODY、HTML

parentsUntil 查找父元素直到指定元素

复制代码
import * as cheerio from "cheerio";

const html = `
    <div class="container">
      <div class="item">1</div>
      <div class="item">2</div>
      <div class="item">3</div>
    </div>
    `;
const $ = cheerio.load(html);
const parents = $(".item").parentsUntil("body");
parents.each((index, element) => {
  console.log($(element).prop("tagName"));
});

closest 查找最近的父元素

复制代码
import * as cheerio from "cheerio";

const html = `
    <div class="container">
      <div class="item">1</div>
      <div class="item">2</div>
      <div class="item">3</div>
    </div>
    `;
const $ = cheerio.load(html);
const result = $(".item").closest(".container");
console.log(result.prop("class")); // 输出: container

next, prev 查找下一个或上一个兄弟元素

复制代码
import * as cheerio from "cheerio";

const html = `
    <div class="container">
      <div class="item">1</div>
      <div class="item">2</div>
      <div class="item">3</div>
    </div>
    `;
const $ = cheerio.load(html);

const next = $(".item:first-child").next();
console.log(next.text()); // 输出: 2

const prev = $(".item:last-child").prev();
console.log(prev.text()); // 输出: 3

nextAll, prevAll 查找所有下一个或上一个兄弟元素

复制代码
import * as cheerio from "cheerio";

const html = `
    <div class="container">
      <div class="item">1</div>
      <div class="item">2</div>
      <div class="item">3</div>
    </div>
    `;
const $ = cheerio.load(html);

const nextAll = $(".item:first-child").nextAll();
nextAll.each((index, element) => {
  console.log($(element).text());
});
// 输出: 2、3

const prevAll = $(".item:last-child").prevAll();
prevAll.each((index, element) => {
  console.log($(element).text());
});
// 输出: 1、2

siblings 查找所有兄弟元素

复制代码
import * as cheerio from "cheerio";

const html = `
    <div class="container">
      <div class="item">1</div>
      <div class="item">2</div>
      <div class="item">3</div>
    </div>
    `;
const $ = cheerio.load(html);

const siblings = $(".item:first-child").siblings(); // 输出: 2、3

nextUntil, prevUntil 查找下一个或上一个兄弟元素直到指定元素

复制代码
import * as cheerio from "cheerio";

const html = `
    <div class="container">
      <div class="item">1</div>
      <div class="item">2</div>
      <div class="item">3</div>
    </div>
    `;
const $ = cheerio.load(html);

const nextUntil = $(".item:first-child").nextUntil(".item:last-child");
nextUntil.each((index, element) => {
  console.log($(element).text());
});
// 输出: 2

const prevUntil = $(".item:last-child").prevUntil(".item:first-child");
prevUntil.each((index, element) => {
  console.log($(element).text()
})
// 输出: 3

eq 查找指定索引的元素

复制代码
import * as cheerio from "cheerio";

const html = `
    <div class="container">
      <div class="item">1</div>
      <div class="item">2</div>
      <div class="item">3</div>
    </div>
    `;
const $ = cheerio.load(html);

const result = $(".item").eq(1);
console.log(result.text()); // 输出: 2

filter 查找符合条件的元素

复制代码
import * as cheerio from "cheerio";

const html = `
    <div class="container">
      <div class="item">1</div>
      <div class="item book">2</div>
      <div class="item">3</div>
    </div>
    `;
const $ = cheerio.load(html);
const result = $(".item").filter(".book");
console.log(result.text()); // 输出: 2

not 查找不符合条件的元素

复制代码
import * as cheerio from "cheerio";

const html = `
    <div class="container">
      <div class="item">1</div>
      <div class="item book">2</div>
      <div class="item">3</div>
    </div>
    `;
const $ = cheerio.load(html);

const result = $(".item").not(".book");
result.each((index, element) => {
  console.log($(element).text());
});
// 输出: 1、3

has 查找包含指定子元素的元素

复制代码
import * as cheerio from "cheerio";

const html = `
    <div class="container">
      <div class="item">1</div>
      <div class="item book">
        <b>2</b>
      </div>
      <div class="item">3</div>
    </div>
    `;
const $ = cheerio.load(html);

const result = $(".item").has("b");
console.log(result.length); // 输出: 1

first, last 查找第一个或最后一个元素

复制代码
import * as cheerio from "cheerio";

const html = `
    <div class="container">
      <div class="item">1</div>
      <div class="item">2</div>
      <div class="item">3</div>
    </div>
    `;
const $ = cheerio.load(html);

const first = $(".item").first();
console.log(first.text()); // 输出: 1

const last = $(".item").last();
console.log(last.text()); // 输出: 3

操作元素

attr 获取或设置属性

复制代码
import * as cheerio from "cheerio";

const html = `
    <div class="container">
      <div class="item">1</div>
      <div class="item">2</div>
      <div class="item">3</div>
    </div>
    `;
const $ = cheerio.load(html);
const result = $(".item").attr("class");
console.log(result); // 输出: item

$(".img").attr("src", "imgUrl");
console.log($(".img").attr("src")); // 输出: imgUrl

class 属性

复制代码
$("div").addClass("new-class");
$("div").removeClass("old-class");
$("div").toggleClass("toggle-class");

text 获取或设置文本内容

复制代码
$("div").text("new text");
console.log($("div").text()); // 输出: new text

html 获取或设置 HTML 内容

复制代码
$("div").html("<p>new html</p>");
console.log($("div").html()); // 输出: <p>new html</p>

append, prepend 在元素内部追加或前置内容

复制代码
$(".item").append("<p>append content</p>");
$(".item").prepend("<p>prepend content</p>");

after, before 在元素外部追加或前置内容

复制代码
$(".item").after("<p>after content</p>");
$(".item").before("<p>before content</p>");

insertAfter, insertBefore 在元素外部追加或前置内容

复制代码
$("<p>insertAfter content</p>").insertAfter("item");
$("<p>insertBefore content</p>").insertBefore("item");

prependTo, appendTo 在元素内部追加或前置内容

复制代码
$("<p>prependTo content</p").prependTo(".item");
$("<p>appendTo content</p").appendTo(".item");

wrap, wrapInner 在元素外部包裹内容

复制代码
$("div").wrap("<div class='wrapper'></div>");
$("div").wrapInner("<div class='wrapper'></div>");

unwrap 移除包裹的元素

复制代码
$("div").unwrap();

replaceWith 替换元素

复制代码
$("div").replaceWith("<p>new content</p>");

empty 清空元素内容

复制代码
$("div").empty();

remove 移除元素

复制代码
$("div").remove();

更多用法

extract

复制代码
import * as cheerio from "cheerio";

const html = `
    <div class="container">
      <div class="item">1</div>
      <div class="item book">
        <b>2</b>
      </div>
      <div class="item">3</div>
    </div>
    `;
const $ = cheerio.load(html);
const data = $.extract({
  book: ".book",
});
console.log(data); // 输出: {"book": "\n        2\n      "}

Configuring 配置

|------------------|-------|-------------------------|
| 类型 | 默认值 | 描述 |
| scriptingEnabled | false | 是否启用脚本 |
| xmlMode | true | 启用 htmlparser2 的 XML 模式 |
| decodeEntities | true | 解码 HTML 实体。 |
| withStartIndices | false | 为节点添加一个startIndex属性 |
| withEndIndices | false | 为节点添加一个endIndex属性 |

Extending 扩展

自定义选择器

复制代码
const html = `
    <div class="container">
      <div class="item">1</div>
      <div class="item book">
        <b>2</b>
      </div>
      <div class="item">3</div>
    </div>
    `;

const $ = cheerio.load(html, {
  pseudos: {
    book: "div.book",
  },
});
console.log($(":book").text()); // 2

自定义方法

复制代码
import * as cheerio from "cheerio";

const html = `
    <div class="container">
      <div class="item">1</div>
      <div class="item book">
        <b>2</b>
      </div>
      <div class="item">3</div>
    </div>
    `;

const $ = cheerio.load(html);
$.prototype.myFunction = function () {
  return "Hello, World!";
};

console.log($(".container").myFunction()); // 输出: Hello, World!

更多用法

相关推荐
anOnion2 天前
构建无障碍组件之Menu Button pattern
前端·html·交互设计
米丘3 天前
vite8 vite preview 命令做了什么?
node.js·vite
米丘3 天前
微前端之 Web Components 完全指南
微服务·html
blanks20203 天前
生成 公钥私钥 笔记
node.js
太岁又沐风4 天前
复现并修掉ART hook框架 Pine 调用原方法时的偶发 SIGSEGV
爬虫
糖拌西瓜皮4 天前
Java开发者视角:深入理解Node.js异步编程模型
java·后端·node.js
智通5 天前
Node.js事件循环核心机制
node.js
隔窗听雨眠5 天前
大模型加爬虫上篇:技术融合与架构革新
爬虫·架构
Metaphor6925 天前
使用 Python 将 PDF 转换为 HTML
python·pdf·html
a1117765 天前
“黑夜流星“个人引导页 网页html
java·前端·html