@bonniernews/atlas-html-stream

中文文档
2.0.1发布于 2021/12/21Apache-2.0CommonJS零依赖近 30 天下载 2466

一个超快的html-parser流输出标记,文本和关闭节点.

中文使用文档
文档目录10 节
  1. 安装
  2. 为什么
  3. 业绩
  4. 实例
  5. 有管道
  6. 无管道
  7. 注释、脚本和样式节点
  8. 保持空白空间
  9. 待办事宜
  10. 说明

地图集-html-流

Built latest

叉子为 地图集-html-流 它是一个超快的html-parser流 输出标记, 文本和关闭节点。 见 CHANGELOG.md 用于在分叉中引入的更改.


安装

npm install --save @bonniernews/atlas-html-stream

为什么

我不喜欢 htmlparser2 的流 API , 我想要一个 html 解析器,在默认情况下 连接文本节点的白空间。 我还想看看能不能写一个更快的解析器.

业绩

htmlparser 基准标记

以下基准是用我的本地机器 htmlparser 基准标记下调更好 :

atlas-html-stream: 4.91208 ms/file ± 6.08846
htmlparser2: 7.06549 ms/file ± 5.09643

我只测试了htmlparser2,因为它是最快的以流为基础的剖析器. 这个基准使用两个解析器的流出界面.

内存使用量

一个简单的解析器需要身体在内存中,如果您的 HTML 非常大,则可能打破游戏. 这个解析器是一个流, 并且从使用块数据中受益 。 基本的想法是跟踪当前块 以及从上一个块溢出到当前块的任何东西。 例如,考虑以下两个块:

  1. "first data chunk <di"
  2. "v>second chunk</div>"

当解析器用第一个块完成时,它会认识到它需要坚持 "<di" 而只会冲出 "first chunk " 从记忆。 当解析器用第二块完成后,它会冲出记忆中的一切,因为不再有一个待决的节点.

实例

使用这个解析器很容易 extends 流界面 - 您只需要管道或写入 HTML 并听 "data" 事件:

有管道

建议使用流界面,因为它允许您消耗一定数量的内存(无论HTML大小):

const { createReadStream } = require("fs");
const HtmlParser = require("@bonniernews/atlas-html-stream");
const myHtmlFile = createReadStream("./index.html");

myHtmlFile.pipe(new HtmlParser()).on("data", ({name, data, text}) => {
  if (text){
    // is a text node
    console.log(text);
  } else if (name && data){
    // is an opening tag with potential attributes
    console.log(name, data)
  } else {
    // is a closing tag
    console.log(name)
  }
}).on("end", () => {
  console.log("parsed all html")
})

无管道

除非您负担得起您的 HTML 完全存在于内存中,否则不推荐此选项 。 首先,我们将写一个小助手来取出流线界面:

// helpers.js
const HtmlParser = require("@bonniernews/atlas-html-stream");
const parser = new HtmlParser();

const parseHtml = html => {
  const nodes = [];
  parser.on("data", data => nodes.push(data))
  parser.write(html)
  // resets the parser back to vanilla state
  parser.reset();
  return nodes;
}

module.exports = { parseHtml };

接下来,我们将使用我们的助手来分析我们的内幕html文件:

const { readFileSync } = require("fs");
const { parseHtml } = require("./helpers");
const file = readFileSync("./index.html");
const nodes = parseHtml(file);
// do what you want with the parsed nodes.

注释、脚本和样式节点

上面的例子表明API是多么的微不足道,应该如此. 注释,脚本和样式节点被作为正则节点处理,因为它们发出打开和关闭标记. 主要的区别在于,这些节点内部的内容被作为单一的原始文本节点来对待,没有白空-collaps. 简而言之,让我们用我们的 parseHtml 帮助器在以下实例中的功能 :

脚本/样式标签

...
const scriptNodes = parseHtml(`
  <script src="./script.js">
    const myVar = 5;
  </script>
`);
scriptNodes.forEach(n => console.log(n))
// { name: 'script', data: { src: './script.js' } }
// { text: '\n    const myVar = 5;\n  ' }
// { name: 'script' }

样式标记的处理方式相同,但 name 属性的值为 "style"。 。 。 .

注释标签

同样,这些也得到了同样的对待.

const commentNodes = parseHtml(`
  <!--
    this is
    a comment
  -->
`)
commentNodes.forEach(n => console.log(n));
// { name: '!--', data: {} }
// { text: ' \n    this is \n    a comment \n  ' }
// { name: '!--' }

保持空白空间

默认情况下,解析器会将所有非标注/样式/comment 白空降为单个空格,如果您正在刮取并不在乎白空格,则白空格是有用的. 在某些情况下,你需要白空间。 你可以通过一个 preserveWS 选项到构造器,它将迫使解析器保留它在文本节点中找到的所有空白:

const nodes = parseHtml(`
  This is some text

      <b>
        Hola
          </b>
`)
nodes.forEach(n => console.log(n));
// { text: "\n  This is some text\n\n      " }
// { name: "b", data: {} }
// { text: " \n        Hola\n          " }
// { name: "b" }
// { text: "  \n" }

然后,如果需要更具体化的话,可以处理节点。 请注意,这个例子不使用流线接口来简化,但是流线接口被高度推荐:

myFile.pipe(new HtmlParser({preserveWS: true})).pipe(myTransform).on("data", node => {...})

myTransform 可以有条件地检查文本节点,然后逐一处理.

待办事宜

parseHtml 帮助者

应否 parseHtml 除此包外, 还要导出 HtmlParser使用 parseHtml 在流媒体界面上不建议使用,但它似乎是对html字符串需要存在内存的情况的有效帮助.

还要快

我想让这个东西更快。 解析本身需要了解 3.5 ms/file (使用时) htmlparser 基准标记在我的电话机上 将节点推为 data 增加40%左右的处理时间 4.9 ms/file - 这是无法避免的,因为我们 请求 流媒体界面.

这个 SeqMatcher 减慢此解析器( 检查注释, 脚本和样式节点); 可能有一个更快的方法来处理这些特殊的节点 .

正在打开 state 首先是解析器,可能比先切换当前字符要快,但我还没有测试后者。 主要想法是,尽量减少每项指令所需的数量 [state, char] 根据每一对的概率 若为 [TEXT, !whitespace] 在“ 典型” html 中, 概率最高, 那么我们希望这对 需要最少的指令。 换句话说, sum_i(probabilityOfPair_i*numSteps_i) 应尽量减少.

我想是美国崩溃了 SCRIPT, (中文(简体) ), STYLE 财务报告和审定财务报表 COMMENT 变成单一状态 SPECIAL 可能会提高性能 而不是污染空间 SeqMatchers 每个人一开始都可以按需创建,无论哪个 SPECIAL 节点,我们正在解析, 把它们储存在一长串 以防我们看到相同的 SPECIAL 又是节点.

动态解析器想法

什么定义了“典型的”html文档? 一组解析“ 典型” html 文档的指令对于“ 非典型” html 文档可能较慢, 其差异很大 probabilityOfPair_i 分发。 如果解析器可以利用当前文档的对子分布来动态地改变其飞行时的状况呢? 例如,如果我们被原始文本所压倒,那么检查状态会更快 TEXT 先说 或者,如果我们的文件几乎 没有 原始文本,如果状态是 TEXT 最后一个 虽然动态剖析器听起来很有趣,但如果它增加了一吨间接费用,就可能不值得执行.

说明

大文本节点

由于解析器在内存中一直等待节点的数据,一个大的文本节点会引发内存问题. 在绝大多数情况下,你不会碰到比块本身更大的文本节点。 如果这成为问题,可修改解析器以接受 maxTextSize 用于块块单个文本节点的参数。 现在,这是一个极端的边缘案件,没有处理.

文档类型

道克类型节点作为任何其他节点处理. 投入 "<!DOCTYPE html>" 将产生以下数据事件: {name: "!DOCTYPE", data: {html: ""}}

无值的属性

没有值的标记属性不被特殊处理;一个没有值的密钥会在节点的数据字段中有一个空字符串值. 我可以执行 true 作为默认值,但这似乎是可以很容易地由呼叫者完成的.

版本与发布记录

@bonniernews/atlas-html-stream 共发布 4 个版本,首次发布于 2021/08/26;过去 12 个月发布了 0 个版本。

版本发布日期距今
2.0.1latest2021/12/214 年前
2.0.02021/12/084 年前
1.2.22021/08/265 年前
1.2.12021/08/265 年前

关于 @bonniernews/atlas-html-stream 的常见问题

@bonniernews/atlas-html-stream 是什么?

一个超快的html-parser流输出标记,文本和关闭节点.

如何安装 @bonniernews/atlas-html-stream?

在项目目录运行 npm install @bonniernews/atlas-html-stream,或使用 pnpm add / yarn add / bun add。

@bonniernews/atlas-html-stream 支持 TypeScript 吗?

该包的 package.json 没有声明类型入口。需要类型提示时,可以在 npm 上查找社区维护的 @types/bonniernews__atlas-html-stream 是否存在。

@bonniernews/atlas-html-stream 支持 ESM 还是 CommonJS?

以 CommonJS 形式发布,可以直接 require();在 ES Module 项目中也可以用 import 引入(Node.js 会把 module.exports 作为默认导出)。

@bonniernews/atlas-html-stream 需要什么版本的 Node.js?

package.json 的 engines 字段要求 Node.js >=10.1.0。版本不符时 npm 默认只给出警告,开启 engine-strict 后会拒绝安装。

@bonniernews/atlas-html-stream 可以商用吗?

@bonniernews/atlas-html-stream 使用 Apache-2.0 许可。宽松许可:允许商业使用、修改和再分发,并附带明确的专利授权;分发时需保留许可与 NOTICE 文件,修改过的文件要注明改动。以上为概括,不构成法律意见,请以许可原文为准。

@bonniernews/atlas-html-stream 的下载量有多少?

根据 npm 官方下载统计,@bonniernews/atlas-html-stream 在 2026/10/09 – 2026/11/07 这 30 天内被下载 2,466 次,日均约 82 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@bonniernews/atlas-html-stream 还在维护吗?

最新版本 2.0.1 发布于 2021/12/21(4 年前);至今共发布 4 个版本,其中过去 12 个月发布了 0 个;首次发布于 2021/08/26。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。