cheerio、domino、jsdom 和 parse5 都是用于在 Node.js 中处理 HTML 内容的工具,但它们的定位完全不同。cheerio 提供了类似 jQuery 的 API,专注于快速抓取和遍历;jsdom 实现了完整的 Web 标准 DOM,适合需要浏览器环境的测试;domino 是一个轻量级的 DOM 实现,适合对性能敏感的场景;parse5 则是底层的 HTML 解析器,返回抽象语法树,适合构建自定义工具。
在 Node.js 中处理 HTML 是一门技术活。cheerio、domino、jsdom 和 parse5 都能解析 HTML,但它们的内部机制和适用场景差别很大。选错工具可能导致代码运行缓慢,或者无法通过测试。本文将从核心机制、API 风格、环境模拟和实际场景四个方面进行深度对比。
这四个库的根本区别在于它们是否实现了完整的文档对象模型(DOM)。
cheerio 只解析 HTML 并提供遍历 API,不模拟浏览器环境。
window 对象,没有样式计算,没有布局。// cheerio: 仅加载结构
const cheerio = require('cheerio');
const $ = cheerio.load('<html><body><h1>Hello</h1></body></html>');
// 无法访问 window 对象
// console.log(window); // undefined
jsdom 实现了完整的 Web 标准 DOM,包括 window 和 document。
// jsdom: 完整环境
const { JSDOM } = require('jsdom');
const dom = new JSDOM('<html><body><h1>Hello</h1></body></html>');
// 可以访问 window 对象
console.log(dom.window.document.querySelector('h1').textContent);
domino 实现了 DOM 标准,但比 jsdom 更轻量。
document 对象,但通常不包含完整的 window 对象。// domino: 轻量 DOM
const domino = require('domino');
const doc = domino.createDocument('<html><body><h1>Hello</h1></body></html>');
// 有 document,但通常没有 window
console.log(doc.querySelector('h1').textContent);
parse5 只是一个解析器,返回抽象语法树(AST)。
querySelector 或 DOM 遍历方法。// parse5: 纯解析器
const parse5 = require('parse5');
const ast = parse5.parse('<html><body><h1>Hello</h1></body></html>');
// 返回的是 AST 对象,不是 DOM
console.log(ast.childNodes[0].tagName); // 'html'
API 的设计直接影响开发效率。
cheerio 使用类似 jQuery 的链式调用。
// cheerio: jQuery 风格
const $ = cheerio.load('<ul><li class="item">A</li></ul>');
const text = $('.item').text();
// 链式调用
jsdom 使用标准的浏览器 DOM API。
querySelector、addEventListener 等。// jsdom: 标准 DOM 风格
const dom = new JSDOM('<ul><li class="item">A</li></ul>');
const text = dom.window.document.querySelector('.item').textContent;
// 标准 API
domino 也使用标准的 DOM API。
jsdom 的用法非常相似。// domino: 标准 DOM 风格
const doc = domino.createDocument('<ul><li class="item">A</li></ul>');
const text = doc.querySelector('.item').textContent;
// 标准 API
parse5 需要手动遍历 AST。
// parse5: 手动遍历
const ast = parse5.parse('<ul><li class="item">A</li></ul>');
// 需要递归查找节点
function findLi(node) {
if (node.tagName === 'li') return node;
if (node.childNodes) {
for (let child of node.childNodes) {
const res = findLi(child);
if (res) return res;
}
}
}
const li = findLi(ast);
是否需要模拟浏览器全局环境是选择的关键。
cheerio 完全没有环境模拟。
window 或 document 的客户端脚本。// cheerio: 无环境
const $ = cheerio.load('<div></div>');
// 无法执行脚本或触发事件
jsdom 提供完整的 window 对象。
// jsdom: 完整环境
const dom = new JSDOM('<div></div>', { runScripts: 'dangerously' });
dom.window.document.dispatchEvent(new dom.window.Event('click'));
domino 提供 document 但 window 支持有限。
jsdom 好。// domino: 有限环境
const doc = domino.createDocument('<div></div>');
// 通常不推荐用于事件模拟
parse5 不涉及环境模拟。
// parse5: 无环境
const ast = parse5.parse('<div></div>');
// 纯粹的数据结构
你需要从成千上万个页面中提取标题和价格。
cheerio// cheerio 示例
const $ = cheerio.load(html);
const price = $('.price').text();
你需要测试一个依赖 document.querySelector 的组件。
jsdom// jsdom 示例
const dom = new JSDOM(html);
global.document = dom.window.document;
你需要清理用户提交的 HTML,去除危险标签,且并发量很大。
parse5// parse5 示例
const ast = parse5.parse(html);
// 自定义遍历去除脚本标签
你需要操作 DOM 结构,但 jsdom 启动太慢。
dominojsdom 快,且提供了标准的 DOM API。// domino 示例
const doc = domino.createDocument(html);
doc.body.innerHTML = '';
| 特性 | cheerio | jsdom | domino | parse5 |
|---|---|---|---|---|
| 核心类型 | jQuery 兼容层 | 完整 DOM 模拟 | 轻量 DOM 实现 | HTML 解析器 |
| API 风格 | $().find() | document.querySelector | document.querySelector | AST 遍历 |
| Window 对象 | ❌ 无 | ✅ 完整 | ⚠️ 有限/无 | ❌ 无 |
| 执行脚本 | ❌ 不支持 | ✅ 支持 (需配置) | ❌ 不支持 | ❌ 不支持 |
| 性能 | ⚡ 极快 | 🐢 较慢 | ⚡ 快 | ⚡ 极快 |
| 主要用途 | 爬虫、数据提取 | 测试、SSR | 轻量 DOM 操作 | 编译器、工具链 |
cheerio 是爬虫和数据提取的首选工具 — 它简单、快速且足够强大。如果你的任务只是读取 HTML 内容,不要引入更重的库。
jsdom 是测试和模拟浏览器环境的黄金标准 — 当你的代码依赖 window 或 DOM 事件时,它是唯一可靠的选择。尽管它比较重,但兼容性无可替代。
domino 是一个不错的中间选项 — 当你需要 DOM API 但 jsdom 太慢时使用。但要注意它的维护状态不如 jsdom 活跃。
parse5 是底层构建者的工具 — 如果你正在编写一个 HTML 编译器或需要流式处理,它是基础。对于普通业务逻辑,它过于原始。
核心原则:不要为了杀鸡用牛刀。如果只是提取文本,cheerio 就够了;如果需要运行测试,jsdom 是必须的。
选择 parse5 如果你需要构建自己的 HTML 处理工具,或者需要流式解析大文件。它不提供 DOM 操作 API,只负责解析和序列化,适合底层开发。如果你需要完全控制解析过程,选它。
选择 jsdom 如果你需要在 Node.js 中运行依赖浏览器 DOM API 的代码,比如前端单元测试或服务端渲染预演。它是标准兼容性最好的选择,支持窗口对象和事件模拟。
选择 cheerio 如果你需要做网页爬虫或数据提取,且不需要真正的浏览器环境。它的类 jQuery API 学习成本低,处理速度快,适合大多数静态 HTML 分析任务。如果你只需要提取文本或属性,它是最高效的选择。
选择 domino 如果你需要一个轻量的 DOM 环境,但 jsdom 太重了。注意它的维护频率较低,适合内部工具或对标准兼容性要求不高的场景。它在内存占用上比 jsdom 更有优势。
npm install --save parse5
📖 Documentation 📖