
Product
A Fresh Look for the Socket Dashboard
We’ve redesigned the Socket dashboard with simpler navigation, less visual clutter, and a cleaner UI that highlights what really matters.
一个基于 Cheerio 的强大 HTML 解析和数据提取工具库,专为简化网页数据抓取而设计。
selector@attribute
- 直接提取属性值[selector]
- 获取所有匹配元素:not-empty
- 扩展的伪选择器selector | filter1 | filter2
- 链式数据处理.string()
, .nextNode()
, .extract()
, .extractAll()
npm install cparse
系统要求:Node.js >= 18.17.0
const { loadCheerio, parse } = require('cparse');
const html = '<div class="title">Hello World</div>';
const $ = loadCheerio(html);
// 传统用法
const title = parse('.title', $); // "Hello World"
// 🎯 新增:简化语法 - 直接在 $ 实例上调用 parse
const title2 = $.parse('.title'); // "Hello World"
// 数组提取(语法糖)
const items = $.parse('[.item]'); // 所有 .item 元素的文本数组
// 属性提取(语法糖)
const links = $.parse('[a@href]'); // 所有链接的 href 属性数组
// 过滤器链
const price = $.parse('.price | trim | float'); // 文本 -> 去空格 -> 转浮点数
// ❌ 传统用法:需要传递 $ 参数
const title = parse('.title', $);
const data = parse({ title: '.title', count: '.count | int' }, $);
// ✅ 简化用法:直接在 $ 实例上调用
const title = $.parse('.title');
const data = $.parse({ title: '.title', count: '.count | int' });
const html = `
<div class="product">
<h2 class="title">iPhone 15</h2>
<span class="price">$999.00</span>
<div class="rating" data-score="4.5">★★★★☆</div>
</div>
`;
const $ = loadCheerio(html);
// 使用简化语法提取结构化数据
const product = $.parse({
title: '.title',
price: '.price | regex:\\d+\\.\\d+ | float',
rating: '.rating@data-score | float'
});
console.log(product);
// { title: "iPhone 15", price: 999.00, rating: 4.5 }
const axios = require('axios');
const { cheerioHookForAxios, parse } = require('cparse');
const client = axios.create();
cheerioHookForAxios(client);
// 响应自动包含 $ 属性,可以直接使用简化语法
const response = await client.get('https://example.com');
const title = response.$.parse('title');
const links = response.$.parse('[a@href]');
const got = require('got');
const { cheerioHookForGot, parse } = require('cparse');
const client = got.extend({});
cheerioHookForGot(client);
const response = await client.get('https://example.com');
const data = response.$.parse({
title: 'title',
description: 'meta[name="description"]@content'
});
v2.0.2+ 新增功能:现在可以直接在 Cheerio 实例上调用 parse
方法,无需传递 $
参数!
传统用法 | 简化用法 | 说明 |
---|---|---|
parse('.title', $) | $.parse('.title') | 基本选择器 |
parse('[.item]', $) | $.parse('[.item]') | 数组提取 |
parse('a@href', $) | $.parse('a@href') | 属性提取 |
parse('.price | float', $) | $.parse('.price | float') | 过滤器链 |
parse({...}, $) | $.parse({...}) | 结构化数据 |
const { loadCheerio } = require('cparse');
const $ = loadCheerio('<div class="title">Hello</div>');
// ✅ 推荐:使用简化语法
const title = $.parse('.title');
const data = $.parse({
title: '.title',
items: '[.item]',
link: 'a@href'
});
// ❌ 传统用法(仍然支持)
const { parse } = require('cparse');
const title2 = parse('.title', $);
cparse 的核心价值在于提供简洁的语法糖,简化常见的数据提取操作:
@
// 传统 Cheerio 写法
$('a').map((i, el) => $(el).attr('href')).get();
// cparse 简化语法
$.parse('[a@href]');
[]
// 传统 Cheerio 写法
$('.item').map((i, el) => $(el).text()).get();
// cparse 简化语法
$.parse('[.item]');
// 完全支持 Cheerio 原生 CSS 选择器
$.parse('div.active'); // 类选择器
$.parse('input[type="text"]'); // 属性选择器
$.parse('li:first-child'); // 伪选择器
// :not-empty 伪选择器(Cheerio 原生不支持)
parse('p:not-empty', $); // 转换为 p:not(:empty)
cparse 提供了 30+ 内置过滤器,支持链式调用进行复杂的数据处理:
// 过滤器链示例
parse('.price | trim | regex:\\d+\\.\\d+ | float', $);
// 文本 -> 去空格 -> 正则提取 -> 转浮点数
过滤器 | 功能 | 示例 |
---|---|---|
int | 转换为整数 | parse('.count | int', $) |
float | 转换为浮点数 | parse('.price | float', $) |
bool | 转换为布尔值 | parse('.active | bool', $) |
过滤器 | 功能 | 示例 |
---|---|---|
trim | 去除首尾空白 | parse('.title | trim', $) |
slice | 字符串切片 | parse('.text | slice:0:10', $) |
regex | 正则表达式匹配 | parse('.text | regex:\\d+', $) |
replace | 字符串替换 | parse('.text | replace:old:new', $) |
split | 字符串分割 | parse('.text | split:,', $) |
upper/lower | 大小写转换 | parse('.text | upper', $) |
capitalize | 首字母大写 | parse('.text | capitalize', $) |
title | 标题格式化 | parse('.text | title', $) |
过滤器 | 功能 | 示例 |
---|---|---|
length | 获取长度 | parse('[.items] | length', $) |
first/last | 首/末元素 | parse('[.items] | first', $) |
unique | 数组去重 | parse('[.items] | unique', $) |
sort | 数组排序 | parse('[.items] | sort', $) |
compact | 过滤空值 | parse('[.items] | compact', $) |
join | 数组连接 | parse('[.items] | join:-', $) |
过滤器 | 功能 | 示例 |
---|---|---|
date | 日期解析 | parse('.date | date', $) |
size | 尺寸解析 | parse('.filesize | size', $) |
number | 数字格式化 | parse('.price | number:2', $) |
default | 提供默认值 | parse('.optional | default:"N/A"', $) |
default
过滤器处理缺失值在抓取数据时,经常会遇到某些字段缺失的情况。如果一个选择器没有匹配到任何元素,解析结果通常是 null
,这可能导致后续的过滤器(如 float
)出错。使用 default
过滤器可以优雅地处理这种情况:
const { loadCheerio } = require('cparse');
const html = `
<div class="product">
<span class="name">Product A</span>
<span class="price">$19.99</span>
</div>
<div class="product">
<span class="name">Product B</span>
// 价格缺失
</div>
`;
const $ = loadCheerio(html);
const products = $.parse(['.product', {
name: '.name',
// 如果 .price 不存在,结果为 null,float(null) 会是 NaN
// 使用 default 过滤器提供一个默认值 0
price: '.price | float | default:0'
}]);
console.log(products);
// [
// { name: 'Product A', price: 19.99 },
// { name: 'Product B', price: 0 }
// ]
loadCheerio(html, options?, baseUrl?)
加载 HTML 并返回扩展的 Cheerio 实例
const $ = loadCheerio('<div>Hello</div>', {}, 'https://example.com');
parse(rule, $, filters?)
数据解析核心函数
// 字符串规则
parse('h1', $)
// 对象规则
parse({ title: 'h1', links: '[a@href]' }, $)
// 数组规则(分割器语法)
parse(['[.item]', { name: '.name', price: '.price | float' }], $)
cheerioHookForAxios(instance, options?)
为 Axios 添加 Cheerio 支持
cheerioHookForGot(instance, options?)
为 Got 添加 Cheerio 支持
语法 | 说明 | 示例 |
---|---|---|
selector | 标准 CSS 选择器 | parse('h1', $) |
selector@attr | 属性提取语法糖 | parse('a@href', $) |
[selector] | 数组提取语法糖 | parse('[.item]', $) |
selector | filter | 过滤器链 | parse('.price | float', $) |
// 完全支持 Cheerio 原生 CSS 选择器
parse('div.active', $) // 类选择器
parse('input[type="text"]', $) // 属性选择器
parse('li:first-child', $) // 伪选择器
// 语法糖(cparse 扩展)
$.parse('p:not-empty')
// 转换为 Cheerio 原生
$.parse('p:not(:empty)')
// 直接使用 Cheerio 原生选择器
parse('nav > ul > li:first-child', $)
parse('input[type="text"]:focus', $)
parse('p:contains("重要")', $)
const data = parse({
title: 'h1',
price: '.price | float',
tags: '[.tag]',
link: 'a@href'
}, $);
const items = parse([
'[.product]', // 分割器:每个 .product 元素
{
name: '.name',
price: '.price | float',
inStock: '.stock | bool'
}
], $);
const result = parse([
'.content',
text => text.toUpperCase(),
text => text.trim()
], $);
cparse 为 Cheerio 添加了便捷的扩展方法:
方法 | 功能 | 示例 |
---|---|---|
.string() | 纯文本内容(不含子元素标签) | $('.content').string() |
.nextNode() | 下一个兄弟节点的文本 | $('.label').nextNode() |
.extract(attr) | 提取单个元素的属性/内容 | $('.item').extract('href') |
.extractAll(attr) | 提取所有元素的属性/内容 | $('.items').extractAll('text') |
在 extract()
和 extractAll()
中可使用的特殊属性:
text
: 文本内容html
: HTML 内容outerHtml
: 包含元素本身的 HTMLstring
: 纯文本内容nextNode
: 下一个兄弟节点文本cparse 提供完善的错误处理机制:
try {
parse('.text | unknownFilter', $);
} catch (error) {
if (error.name === 'FilterError') {
console.log(`过滤器错误: ${error.filterName}`);
console.log(`可用过滤器: ${error.context.availableFilters}`);
}
}
// 第一次解析会缓存结果
parse('h1', $);
// 第二次使用相同查询直接使用缓存
parse('h1', $); // 更快
// ✅ 推荐:一次性提取所有数据
const data = parse({
titles: '[h1]',
links: '[a@href]',
prices: '[.price | float]'
}, $);
// ❌ 避免:多次单独查询
🎯 核心优化
🚀 保留的核心价值
selector@attribute
[selector]
:not-empty
🗑️ 移除的重复功能
欢迎提交 Issue 和 Pull Request!
# 克隆项目
git clone https://github.com/your-username/cparse.git
# 安装依赖
npm install
# 运行测试
npm test
# 运行 lint
npm run lint
MIT License - 详见 LICENSE 文件
⭐ 如果这个项目对你有帮助,请给个 Star!
v2.1.0+ 新增功能:cparse
引入了通用的插件创建工厂函数 createCheerioHook
,允许你为任何 HTTP 客户端(或任何返回 HTML 的数据源)轻松创建集成插件。
cheerioHookForAxios
和 cheerioHookForGot
内部就是使用这个工厂函数实现的。
createCheerioHook(options)
这个函数接受一个配置对象,并返回一个标准的钩子函数。
配置项 options
:
name
(string
, 必需): 插件的名称,用于错误和警告信息 (例如: 'node-fetch'
)。validate(instance)
(function
, 必需): 一个函数,用于验证传入的客户端实例是否有效。如果无效,应返回 false
。attach(instance, hookFn)
(function
, 必需): 一个函数,负责将核心处理逻辑 (hookFn
) 附加到客户端实例的生命周期钩子上(例如,在响应完成后执行)。getBody(response)
(function
, 必需): 一个函数,告诉 cparse
如何从客户端的响应对象中提取 HTML 文本。getUrl(response)
(function
, 必需): 一个函数,用于从响应对象中获取最终的请求 URL,这对于解析页面上的相对链接至关重要。node-fetch
创建集成插件下面是一个完整的示例,展示了如何为 node-fetch
(v3+)封装一个解析钩子。
const fetch = require('node-fetch');
const { createCheerioHook, parse } = require('cparse');
// 1. 使用 createCheerioHook 定义针对 node-fetch 的钩子
const cheerioHookForFetch = createCheerioHook({
name: 'node-fetch',
// 验证 fetch 函数本身(在这个例子中我们直接扩展 fetch)
validate: (instance) => typeof instance === 'function',
// getBody 和 getUrl 是异步的,所以 attach 也要是 async
getBody: async (response) => await response.text(),
getUrl: (response) => response.url,
// 核心:替换原始的 fetch 函数
attach: (originalFetch, hook) => {
// 返回一个新的、被包装过的 fetch 函数
return async (...args) => {
const response = await originalFetch(...args);
// 调用我们通用的处理逻辑
// 注意:由于 getBody 是异步的,这里也需要 await
return await hook(response);
};
},
});
// 2. 包装原始的 fetch 函数
const enhancedFetch = cheerioHookForFetch(fetch);
// 3. 使用增强后的 fetch
async function main() {
const response = await enhancedFetch('https://example.com');
const title = response.$.parse('title');
console.log(title); // "Example Domain"
}
main();
通过这种方式,你可以将 cparse
的解析能力无缝集成到任何你选择的工具中。
FAQs
一个基于 Cheerio 的 HTML 解析和数据提取工具库
The npm package cparse receives a total of 99 weekly downloads. As such, cparse popularity was classified as not popular.
We found that cparse demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Product
We’ve redesigned the Socket dashboard with simpler navigation, less visual clutter, and a cleaner UI that highlights what really matters.
Industry Insights
Terry O’Daniel, Head of Security at Amplitude, shares insights on building high-impact security teams, aligning with engineering, and why AI gives defenders a fighting chance.
Security News
MCP spec updated with structured tool output, stronger OAuth 2.1 security, resource indicators, and protocol cleanups for safer, more reliable AI workflows.