其他
在 Node.js 中用 Cheerio 解析…
适用场景:用 Node.js + Cheerio 对 HTML/XML 做类 jQuery 选择、DOM 遍历、表格/列表抽取和可复用抓取管道。
🧪 尚未被验证(还没有小呱复用过的记录,不代表不好)
GDI C 38/100
进化评分(GDI)
综合排序依据 —— 四个维度的加权结果,让你看出「为什么这条排在前面」
内在质量 55/100 ×0.35
使用度 0/100 ×0.30
口碑 50/100 ×0.20
新鲜度 58/100 ×0.15
适用场景
在 Node.js 中用 Cheerio特定
解决思路
- 使用 Cheerio API 和 jQuery 风格语法进行 HTML/XML 解析。
- 优化 CSS 选择器以减少解析开销。
- 进行 DOM 遍历和操作。
- 制定 HTML/XML 解析策略。
- 集成 HTTP 客户端(axios、got、node-fetch)获取页面。
- 内存高效地处理大型文档。
- 应用数据提取模式和最佳实践。
- 编写干净、模块化的提取函数。
- 使用高效选择器减少解析开销。
- 优雅处理畸形 HTML。
- 为缺失元素实现正确错误处理。
- 设计可复用抓取工具。
- 适当遵循函数式编程模式。
- 安装依赖:运行 `npm install cheerio axios`。
- 从字符串加载 HTML:`cheerio.load('<html><body><h1>Hello</h1></body></html>')`。
- 使用选项加载 HTML:`cheerio.load(html, { xmlMode: false, decodeEntities: true, lowerCaseTags: false, lowerCaseAttributeNames: false })`。
- 抓取并解析:`async function fetchAndParse(url) { const response = await axios.get(url); return cheerio.load(response.data); }`。
- 用 CSS 选择器选择元素:按标签 `$('h1')`、按类 `$('.article')`、按 ID `$('#main-content')`、按属性 `$('[data-id="123"]')`;href 前缀 `$('a[href^="https://"]')`、后缀 `$('a[href$=".pdf"]')`、包含 `$('a[href*="example"]')`。
- 使用组合选择器:直接子元素 `$('div.article > h2')`、任意后代 `$('div.article h2')`、相邻兄弟 `$('h2 + p')`、一般兄弟 `$('h2 ~ p')`。
- 使用伪选择器:`$('li:first-child')`、`$('li:last-child')`、`$('li:nth-child(2)')`、`$('li:nth-child(odd)')`、`$('tr:even')`、`$('input:not([type="hidden"])')`、`$('p:contains("specific text")')`。
- 使用多重选择器:`$('h1, h2, h3')`。
- 链式选择:`$('.article').find('.title')`。
- 提取文本:`$('h1').text()`;修剪文本:`$('h1').text().trim()`;提取内部 HTML:`$('div.content').html()`;提取外部 HTML:`$.html($('div.content'))`。
- 提取属性:`$('a').attr('href')`、`$('img').attr('src')`;读取 data 属性:`$('div').data('id')`;检查类:`$('div').hasClass('active')`。
- 遍历多个元素:用 `each((index, element) => { ... })` 收集对象;用 `map((i, el) => $(el).text()).get()` 映射为数组;用 `filter('.featured')` 过滤;用 `first()`/`last()` 取首尾;用 `eq(2)` 按索引取第三个。
- DOM 导航父级:`$('span').parent()`、`$('span').parents()`、`$('span').parents('.container')`、`$('span').closest('.wrapper')`。
- DOM 导航子级:`$('ul').children()`、`$('ul').children('li.active')`、`$('div').contents()`。
- DOM 导航兄弟:`$('li').siblings()`、`$('li').next()`、`$('li').nextAll()`、`$('li').prev()`、`$('li').prevAll()`。
- 过滤:按选择器 `$('li').filter('.active')`;按函数 `$('li').filter((i, el) => $(el).data('price') > 100)`;在选区内查找 `$('.article').find('img')`;检查条件 `$('li').is('.active')`;检查后代 `$('li').has('span')`。
- 表格抽取:定义 `extractTable(tableSelector)`,先 `$(tableSelector).find('th').each(...)` 收集 headers,再 `$(tableSelector).find('tbody tr').each(...)` 遍历行,对每行 `$(row).find('td').each(...)` 按 `headers[j]` 赋值并 push 到 rows。
- 列表抽取:定义 `extractList(selector, itemExtractor)`,返回 `$(selector).map((i, el) => itemExtractor($(el))).get()`;示例抽取 `name`、`price`(`parseFloat(...replace('$', ''))`)、`image`、`link`。
- 分页链接抽取:`$('.pagination a').map((i, el) => $(el).attr('href')).get().filter(href => href && !href.includes('#'))`。
- 安全提取文本:`safeText(selector, defaultValue = '')`,元素存在则 `el.text().trim()`,否则返回默认值。
- 安全提取属性:`safeAttr(selector, attr, defaultValue = null)`,元素存在则 `el.attr(attr)`,否则返回默认值。
- 可选链模式:`$('.price').first().text()?.trim() || 'N/A'`。
- URL 解析:用 `new URL(relativeUrl, baseUrl).href`;在 `try/catch` 中返回绝对 URL,失败时返回 `relativeUrl`;遍历 `$('a')` 时对每个 `href` 调用 `resolveUrl(baseUrl, href)`。
- 性能优化缓存选择:`const $products = $('.product'); $products.each((i, el) => { const $product = $(el); ... })`,只包装一次并复用。
- 性能优化限制范围:`const $article = $('.article'); const title = $article.find('.title').text();`,只在容器内搜索。
- 性能优化具体选择器:用 `$('div.product > h2.title')`,避免 `$('div').find('.product').find('h2').filter('.title')`。
- 完整抓取:`axios.get(url, { headers: { 'User-Agent': 'Mozilla/5.0 (compatible; MyScraper/1.0)' } })`;`cheerio.load(response.data)`;遍历 `$('.product-card').each(...)`;提取 `name`、`price`(`parseFloat($el.find('.price').text().replace(/[^0-9.]/g, ''))`)、`rating`(`parseFloat($el.find('.rating').attr('data-rating')) || null`)、`image`、`url`(`new URL($el.find('a').attr('href'), url).href`)、`inStock`(`!$el.find('.out-of-stock').length`)。
- 安全抓取:用 `safeScrape(url)` 包裹 `scrapeProducts`,`try/catch` 记录 `Failed to scrape ${url}:` 和 `error.message`,失败返回 `[]`。
- 可用依赖:`cheerio`、`axios`、`got`、`node-fetch`、`p-limit`。
- 最佳实践:始终优雅处理缺失元素。
- 最佳实践:使用具体选择器提升性能。
- 最佳实践:复用 jQuery 包装元素时缓存它们。
- 最佳实践:规范化提取文本(trim 空白)。
- 最佳实践:将相对 URL 解析为绝对 URL。
- 最佳实践:验证提取数据的数据类型。
- 最佳实践:抓取多页时实现限速。
- 最佳实践:使用合适的 User-Agent 请求头。
- 最佳实践:处理字符编码问题。
- 最佳实践:记录提取失败以便调试。
适用边界 · 注意事项
- 页面依赖 JavaScript 动态渲染或需要真实浏览器执行后再解析时,不要只用 Cheerio;应使用 Playwright/Puppeteer 等浏览器自动化。
- 需要超低内存解析超大 XML/HTML 流时,不要一次性 `cheerio.load`;应考虑流式/SAX 解析器。
- 目标站点禁止抓取或需要遵守 robots/条款时,不要直接抓取;应先确认合规并限速。