@citation-media/html-parser

中文文档
0.8.2发布于 2026/11/04MITTypeScriptES Module构建来源已验证近 30 天下载 2042

HTML 解析器用于任何 JavaScript 运行时间:链接,图像,资源,元数据,JSON-LD,样式,水分,以及文本在一次通过中没有DOM,由mdream的Markdown.

中文使用文档
文档目录14 节
  1. 安装
  2. 解析 A 页
  3. 隐藏内容
  4. 多个需要的一次通行证
  5. 头
  6. 水分
  7. 第一个屏幕
  8. 读取页面样式
  9. 清除页面
  10. 标记
  11. 限制
  12. 开发
  13. 释放
  14. 许可证

@ 引用- 媒体/ html- parser

将链接、图像、资源、元数据、标题、类数、JSON-LD、样式、水合物、可见文本和内线代码从HTML中取出,放在页面上一个转接处,写成Markdown 梦想 从被询问时的相同输入。 它用mdream的活化剂来读取页面,它从来没有建立DOM,在Cloudflare Workers,Node.js,Bun,Deno,和浏览器中以平版JavaScript来运行:一个由数兆字节组成的流出页面,其内存成本大约与一个小的一样多.

安装

npm install @citation-media/html-parser @mdream/js

@mdream/js 是一个同伴依赖, ^1.7.2 或者说 ^2.0.3。 。 。 . 取消标题 一起来 head 选项. cleanHtml 以 HTML 重写器 并且只在全球范围内运行: 云旗工人, wrangler dev,以及 @cloudflare/vitest-pool-workers。 。 。 .

解析 A 页

parseHtml 只返回您想要的。 输入是作为文本的页面, a Response 因此 fetch,或一个 ReadableStream ; 反应或流被逐块读取. parseHtmlSync 对于没有承诺的文字,也要这样做.

import { parseHtml } from "@citation-media/html-parser";

const response = await fetch("https://example.com/");
const { links, images, meta } = await parseHtml(response, {
  url: response.url,
  links: { kinds: ["internal"], resources: false },
  images: true,
  meta: true,
});
选项它收集的东西
url要求。 解析相对的URL,并从外部显示内部链接.
linkstrue 或过滤器 : kinds (单位:千美元)internal, (中文(简体) ), external, (中文(简体) ), special, (中文(简体) ), anchor和 resources: false 来降低PDF等下载.
images图像带有 alt (单位:千美元)null 当失踪时, "" 当装饰的时候, width, (中文(简体) ), height, (中文(简体) ), loading,他们是否有 srcset,其URL为 sources,绝对,没有数据URL,最多20个.
resources脚本 src, (中文(简体) ), type,属性名称,以及它们是否存在于 <head>,帧 URL, <link> 要素 rel 并且,当他们有一个, type,例如 text/markdown 用于页面的Markdown版本,以及 media,音频、视频、其来源和音轨的URL,a <picture>源头,嵌入物和物体,每个都一次. 头部没有经典脚本 async, (中文(简体) ), defer,或 nomodule 屏蔽第一个渲染.
meta标题、描述、语言、犬形URL、机器人、取景口、生成器、Open Graph 图像以及 properties,每个 <meta property> 例如 og:title 或者说 article:published_time 根据其小写财产,第一个重复,最多50个。 标题是文件的第一个 <title>; 一个 SVG 的 <title> 命名图形,不计数.
headings前200个标题及其级别和文本,以及 headingCounts 每个水平无限制.
classPrefixes以前缀开头的元素数, 如 ["elementor-", "brxe-", "wp-block-"]。 。 。 .
contextCSS 等选择器 main 或者说 article: 只计算匹配元素内的内容。 当没有匹配时,整页都算数. 它需要类型, #id, (中文(简体) ), .class属性选择器 =, (中文(简体) ), ~=, (中文(简体) ), |=, (中文(简体) ), ^=, (中文(简体) ), $=, (中文(简体) ), *= 还有一个 i 旗帜, :first-child, (中文(简体) ), :nth-child(), (中文(简体) ), :first-of-type, (中文(简体) ), :nth-of-type(), (中文(简体) ), :not(),和后代和 > 组合器, 如 HTML Rewriter 所做的; 需要元素后出现的选择器, 如 :last-child 或者说 +,丢出一个 SyntaxError。 。 。 .
structuredData该页的JSON -LD作为 items,每个节点 <script type="application/ld+json"> 带有列表和 @graph 扩大 invalid,以位置和出错表示无效的块。 无论区块在哪里,都读取 context。 。 。 .
styles页面本身的 CSS 用于 readStyles数字 : blocks,每个 <style> 块中的文本 id· ; attributes,每个 style 属性及其元素,例如 div#hero.banner; 和 : stylesheets的绝对 URL rel="stylesheet" 链接和样式表预装 as="style"编辑 context。 。 。 .
hydration将浏览器中的页面水化的框架,或 null,参见 水分编辑 context。 。 。 .
positions添加一个 position 每个图像和Astro岛 第一个屏幕编辑 context。 。 。 .
hidden标记每个链接、图像和隐藏内容 hidden,参见 隐藏内容数字 : true 上面写着什么 或规则 (tag, attributes, byMarkup) => boolean 这决定给了它。 直观中重复的链接或图像不被隐藏.
text访问者所读的文本如下: length 财务报告和审定财务报表 content:没有头,脚本,样式,模板, <noscript>,而SVG,白空间倒塌并被一个空间分隔出块状元素. { maxLength } 削减 content100,000个字符默认; length 计算整个文本。 里面的文字很少, 因为上面写着一个脚本的页面.
inlineCode内容安全政策必须允许: scripts,浏览器运行的每个内置脚本的文本,精确地写成散列,没有JSON-LD等数据块或模板; eventHandlers,属性,例如 onclick· ; javascriptUrls 内 href, (中文(简体) ), src, (中文(简体) ), action,以及 formaction· ; styleElements 财务报告和审定财务报表 styleAttributes; 和 : formActions,发送到的绝对 URL 表格。 阅读不管 context。 。 。 .
ids目标为诸如: #team 可以指: 每个元素的 id 和每个 <a>是因为 name,按页面顺序,每页一次,最多5000. 阅读不管 context。将其与 anchor 链接,或与其连接的内部链接的片段,以查找无端链接.
markdown作为Markdown的页面,由mdream从同一份输入中写出: true 对于以完整页面 URL 为基准的mdream 默认,或者mdream 的选项,例如 { plugins: [isolateMainPlugin(), filterPlugin({ exclude: ["nav"] })] } 带有 mdream 2 的插件来源 @mdream/js/plugins明确 origin 覆盖基地。 mdream的滤波器只有Markdown的形状,从来不是其他选项所收集的.
head这个 <head> 作为 取消标题 验证它,看 头编辑 context。 。 。 .
selectCSS 选择器的元素 selected 在同一密钥下: { addresses: "address", times: "time[datetime]" } 给每个匹配的 tag, (中文(简体) ), attributes,以及 text (截至 textContent,没有脚本和样式,切为2000个字符),每个键最多200个,按页面顺序排列 hidden,无论它是隐藏的内容。 选择者就是那些 context 拿着 阅读不管 context。 。 。 .
forms页面表格 : action (绝对;表格名称无的页本身地址), method (单位:千美元)get, (中文(简体) ), post,或 dialog, (中文(简体) ), id 财务报告和审定财务报表 name, (中文(简体) ), fields 与他们的 tag, (中文(简体) ), type (低级病例, text (默认), name, (中文(简体) ), id, (中文(简体) ), autocomplete, (中文(简体) ), placeholder, (中文(简体) ), required,以及 label (单位:千美元) <label> 以 for 或者把它包起来,否则 aria-label),以及 buttons,其按钮的文本。 a外的字段 <form> 不读 hidden,一个表格说它是否是隐藏的内容.

readStructuredData(blocks) 将 JSON- LD 块的文本变成相同的结果, 因为您已经拥有了 。 它只检查每个块是JSON;节点是否包含搜索引擎所期望的属性,由呼叫者决定.

链接被 URL 复制,计数,并按数排序. 每个人带着自己的 text, (中文(简体) ), kind, (中文(简体) ), resource, (中文(简体) ), count,并且,在目前, rel, (中文(简体) ), target,以及 aria-label。 URL是绝对的; 路径保留它们的情况。 文本读作 DOM 的 textContent 有, 实体解码一次, 白空间崩溃 .

隐藏内容

与 hidden,每个链接、图像和标题都表示它是否包含标记隐藏的内容:a <template>页:1 <dialog> 无 open,则 hidden 属性, aria-hidden="true" 或者说 inert,或 display: none 或者说 visibility: hidden 在一个 style 属性。 这是 hidesContent(tag, attributes),导出,以及 hiddenFromReaders(tag, attributes) 这是它的 aria-hidden 财务报告和审定财务报表 inert 部分,其中未包括主要地标<main> 或者说 role="main": 开放模式对话框,如同意对话框,标出其后页 aria-hidden 片刻,不是为好,一个在那个状态中渲染和保存的一页仍然带有标记,而没有任何一页向读者隐瞒其主要内容为好. 课堂上什么也猜不到.

替换规则 true 考虑到标记中所说的,决定每个要素: (tag, attributes, byMarkup) => byMarkup && !attributes.class?.includes("popup") 保持弹出, 它可能有一个印记 (tag, attributes, byMarkup) => byMarkup || /\bsr-only\b/.test(attributes.class ?? "") 也隐藏只读屏幕的文本 。 与 positions,同一决定还告知哪些容器隐藏了它们的内容,除了这些类别之外,估计数还单独列出.

页面所重复的链接或图像只有在每次发生时才会被隐藏:一个被关闭的菜单和页眉中的标志在一目了然. 标题按页面顺序列出,包含隐藏的,所以标题大纲可以跳过或显示. <noscript> 内容是文本给指示器,从未收集.

多个需要的一次通行证

询问所有需要的页面,所以读作一次:

import { parseHtml } from "@citation-media/html-parser";

const page = await parseHtml(await fetch(url), {
  url,
  links: true,
  meta: true,
  structuredData: true,
  text: true,
  markdown: { plugins: { filter: { exclude: ["script", "style"] } } },
});

用于响应或流出 markdown,身体被读取一次,并喂食活化剂和mdream的转换器相并. 事实出自于mdream的活化剂,调制以保持白空间和CSS如页面所拥有;Markdown出自mdream的转换器不变. 在从4 KB到1.9 MB的18页上测量,所有选项加在一起,大约需要较早的HTML Rewriter传出时间的七分之一时间,而用Markdown的四分之一事实加上两次Markdown转换的事实.

头

与 head, (中文(简体) ), parseHtml 手执 <head> 读取为去首: elements 按页面顺序列出标题的元素,每个元素都有其 attributes,其卡波语 weight,则 size 以内含内容的字节表示,标题 text· ; issues 列出未标题的验证器所找到的东西,每个都带有其 rule, 取消标题的英语 message页:1 severity及其索引 element。 。 。 .

const { head } = await parseHtml(html, { url, head: true });
for (const issue of head.issues) {
  console.log(issue.rule, head.elements[issue.element ?? -1]?.attributes);
}

规则是无头的,例如 render-blocking-script, (中文(简体) ), charset-not-early, (中文(简体) ), too-many-preloads, (中文(简体) ), preload-font-crossorigin, (中文(简体) ), preconnect-missing-crossorigin, (中文(简体) ), inline-style-size, (中文(简体) ), non-absolute-canonical, (中文(简体) ), og-image-missing-dimensions,或 viewport-user-scalable。除去头部通常对它制作的标记进行排序并去除;在这里,每个元素都是自己一个重量的条目,所以规则读取了页面的顺序和标记。 关于使用Unhead的API的规则,例如 invalid-input-shape关闭. { head: { rules } } 通过 unhead 的规则配置,例如 { "too-many-preloads": ["warn", { max: 10 }] } 或者说 { "deprecated-twitter-meta": "off" }。 。 。 .

weight 是 Capo 的顺序, 因为它没有标题来计算它: 越低, 越早一个元素属于, 来自 -30 内容-安全政策 -20 以圆柱盟誓, 10 标题,和 50 用于屏蔽脚本,以至 100。一个重量低于一个的元素在它站得比它应该站得晚。 何所报取,而所言取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取.

水分

与 hydration, (中文(简体) ), parseHtml 从HTML中得知,当服务器发送时,不运行脚本,一个框架是否将浏览器中的页面水合,并测量其序列化到HTML中的数据,该数据是浏览器在页面响应输入之前处理的.

framework标记payloadBytes 计数
astro<astro-island> 要素每个岛屿的道具,随着HTML携带它们
next-pages<script id="__NEXT_DATA__">那个脚本
next-app开始的内置脚本 self.__next_f 流线这些脚本
nuxt<script id="__NUXT_DATA__">,或 Nuxt 2's 键 window.__NUXT__ =那个脚本
sveltekit__sveltekit_… = { 内在脚本那个脚本
remixwindow.__remixContext = 或反应路由器 window.__reactRouterContext =那个脚本
angular元素带有 ng-version<script id="ng-state">

payloadBytes 计数字符,对 JSON 来说,框架写的是它的字节。 阿斯特罗的 islands 列出前200个 uid, (中文(简体) ), client 指令, component 文档, propsBytes,以及 serverRendered,这是 false 页:1 client:only 岛屿。 一个标记只计算在内线脚本的前1000个字符中,所以捆绑时没有提及. Qwik 恢复水分而不是水分 null,如同一个脚本在浏览器中渲染而无需服务器给HTML的页面一样.

第一个屏幕

与 positions,每个图像和Astro岛得到一个 position:在滚动前预计在桌面访问时,仅从标记中估算,没有浏览器. 流传的传出没有大小,所以它读出一个元素之前有多少可见的文本和多少图像,以及它是否坐落在一个隐藏的,滑动的,或者固定的容器中,只有在清楚的情况下才能回答:

position何时
hidden标记隐藏在元素内,看 隐藏内容,或者其类标为闭合或只读屏幕的容器,例如 modal, (中文(简体) ), drawer, (中文(简体) ), offcanvas, (中文(简体) ), popover, (中文(简体) ), tooltip, (中文(简体) ), sr-only,或 screen-reader-text。 。 。 .
first-screen可见文本的字符少于200个,且其前没有可见图像.
below之前至少有1500个字符和四分之一的页面可见文本.
unknown一切众生. 旋转木马或滑轮的幻灯片总是 unknown,因为标记时将它们并列;头或固定或粘性容器中的元素从不 below,因为这类集装箱会留在视线内.

文字输入 <nav> 财务报告和审定财务报表 <header>,脚本,样式,模板和隐藏容器不计数. 一个图像的位置是它第一次出现的位置.

从小公司网站WordPress和Astro到SaaS网站和一个有486个图像和岛屿的新闻门户

position估计数对
below184 (韩语)182个不在第一屏幕中:下面135个,47个没有提供
first-screen第28条28个不在下方:第一个屏幕为17个,11个未渲染,例如封闭菜单中的图像
hidden第11个11项未交付
unknown263 (韩语)

这么说吧 below 财务报告和审定财务报表 first-screen 是指某一元素不在或不在第一个屏幕以下的可靠说法,以及 unknown 涵盖所有元素的一半左右. 其出处顺序与所显示内容不同的布局,例如由CSS重排的网格,仍然可以错误地放置一个元素;对于确切的位置,在浏览器中进行测量.

读取页面样式

readStyles 在没有浏览器的情况下,从 CSS 文本中绘制 CSS 定义和使用内容的映射: blocks 财务报告和审定财务报表 attributes parseHtml 以 styles,以及样式表,您可以获取这些样式表,并且,在一个站点的页面中,缓存.

import { parseHtml, readStyles } from "@citation-media/html-parser";

const { styles } = await parseHtml(html, { url, styles: true });
const sheets = await Promise.all(
  styles.stylesheets.map(async (href) => ({
    css: await (await fetch(href)).text(),
    origin: href,
  }))
);
const map = readStyles([
  ...sheets,
  ...styles.blocks.map(({ css, id }) => ({
    css,
    origin: `inline#${id ?? ""}`,
  })),
  ...styles.attributes.map(({ css, element }) => ({
    css,
    element,
    origin: "attribute",
  })),
]);
外地它所持有的
variables每个自定义财产(价值、选择者、来源),有多少声明读取过 var(),而且,如果其根本定义决定了其中之一,则 color 像六分卫一样 定义 :root, (中文(简体) ), html,或 :host 计算页面, 一个外部 @media 先说.
colors每一种颜色都有彩色地产, 和它的正弦, 它的地产, 选择者和来源 variable 宣言本身的颜色没有。 内退 var() 不计为已写入.
fonts每个 font-family 财务报告和审定财务报表 font 声明的第一个家族和整个堆栈,在解析变量之后,用它通过的变量.
fontFaces家属 @font-face 规则加载,有重量,风格, font-display,以及 src,无论描述者的顺序如何.
importsURL( URL) @import 规则装入,按照写法,你也可以得到.

读取器不是完整的 CSS 解析器: 它遵循评论,字符串, 规则, 例如 @media 财务报告和审定财务报表 @layerCSS 嵌入,保留声明的最内层选择器,跳过 @keyframes,而忽略它无法读取的内容。 无所不为:地图上写着CSS写的东西,而不是哪些元素显示出来. readDeclarations(css, origin) 返回一个样式表及其选择者和规则的平面声明.

parseColor 读取六分法, rgb(), (中文(简体) ), hsl(), (中文(简体) ), oklch(), (中文(简体) ), oklab(),并命名颜色为 SRGB; 取决于元素的颜色,例如 currentcolor 或者说 color-mix(),为 null。 。 。 . colorsIn 找到每个颜色的值, toHex 写出一个为六位数的十六进制 colorDistance 测量两种相距有多远(CIE76 in Lab: under 1,眼睛无法分辨它们).

清除页面

cleanHtml 返回 HTML而不包含您删除的内容。 EXIF和XMP块和二进制外观文本总是被去掉.

import { cleanHtml } from "@citation-media/html-parser";

const html = await cleanHtml(page, {
  url: "https://example.com/",
  remove: {
    scripts: true,
    styles: true,
    comments: true,
    cookieConsent: true,
    classes: true,
  },
  links: { kinds: ["internal"] },
  context: "main",
});

remove 接受 scripts, (中文(简体) ), styles (带有样式属性和内置SVG),, comments, (中文(简体) ), cookieConsent, (中文(简体) ), ariaHidden, (中文(简体) ), images, (中文(简体) ), classes, (中文(简体) ), ids, (中文(简体) ), meta, (中文(简体) ), linkTags,以及 hyphenation链接 links 而不成为他们的文本.

cookieConsent 由选择者删除广泛同意工具、 Borlabs Cookie、 Cookiebot、 Usercents、Complianz、 OneTrust、 Real Cookie Banner 等对话框、标语和内容阻断器 consentSelectors 列表; 列表导出给在浏览器中将同意工具从其所读取或测量内容中退出的呼叫者.

ariaHidden 删除屏幕阅读器没有获得的 : aria-hidden="true" 或者说 inert,以及仅用于屏幕阅读器的文本,例如跳过链接。 开放模式对话框, 如同意对话框, 标记其背后的页面 aria-hidden 一瞬间,不是永远的,当对话框打开时,一个页面被渲染和保存,仍然带有标记. 规则 hiddenFromReaders(tag, attributes),导出给自己读取隐藏内容的呼叫者,将主要地标(<main> 或者说 role="main"),没有任何一页对读者隐瞒;任何其他 aria-hidden 或者说 inert 元素计数为隐藏, 因为没有浏览器, 无法显示对话框是否打开 。 浏览器脚本可以添加这个条件.

标记

Markdown本身就是梦: markdown 选项将页面和选项一起交给它。 要使用Mdream的WebAssembly引擎转换,请输入 mdream 软件包,请使用同一文本.

相对的Markdown链接和图像使用完整页面 url 作为他们的基地。 例如,与 url: "https://example.com/guides/start/", (中文(简体) ), next/ 决定: https://example.com/guides/start/next/设置 markdown.origin 摧毁基地.

限制

元素以 HTML 解析器的形式打开并关闭 : <li> 财务报告和审定财务报表 <p> 关闭下一个起始点,元素在页面末尾关闭. cleanHtml 需要 HTML Rewriter, 因此它只在 Cloudflare 的运行时间运行 .

开发

开发需要节点(Node.js 22.18或以后),该节点将装载Oxlint和Oxfmt的TypeScript配置; .nvmrc 针头节点.js 24.

npm ci
npm test
npm run check
npm run build

工作测试 @cloudflare/vitest-pool-workers 和在节点,但 cleanHtml,需要 HTML 写入器.

node --expose-gc bench/parse.mjs <directory of .html files> [dist] [options as JSON] 剖析每页15次,并打印每页的中位数和总数,以比较变化与 main建设( e)npm run build 复制 dist ) (中文(简体) ). 页面不是寄存器的一部分;取几个不同大小的真页.

释放

弹出 version 内 package.json 并添加一节 CHANGELOG.md 打开 main,然后按下匹配标签,例如 v0.2.0. 发布工作流程以出处发布到npm并创建了GitHub发布.

许可证

麻省理工学院

版本与发布记录

@citation-media/html-parser 共发布 14 个版本,首次发布于 2026/09/30;过去 12 个月发布了 14 个版本。最新版本附带 npm provenance 构建来源证明,可追溯到公开的 CI 构建记录。

版本发布日期距今
0.8.2latest2026/11/045 天前
0.8.12026/10/2614 天前
0.8.02026/10/1427 天前
0.7.02026/10/1427 天前
0.6.02026/10/1427 天前
0.5.12026/10/1327 天前

关于 @citation-media/html-parser 的常见问题

@citation-media/html-parser 是什么?

HTML 解析器用于任何 JavaScript 运行时间:链接,图像,资源,元数据,JSON-LD,样式,水分,以及文本在一次通过中没有DOM,由mdream的Markdown.

如何安装 @citation-media/html-parser?

在项目目录运行 npm install @citation-media/html-parser,或使用 pnpm add / yarn add / bun add。它还需要宿主项目提供 peer 依赖:@mdream/js(^1.7.2 || ^2.0.3)。npm 7 及以上与 pnpm 8 及以上默认会自动安装必需的 peer 依赖,Yarn 需要手动安装。

@citation-media/html-parser 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@citation-media/html-parser 支持 ESM 还是 CommonJS?

以 ES Module 形式发布,推荐使用 import 引入。在 CommonJS 项目中,Node.js 20.19+ / 22.12+ 可以直接 require() 不含顶层 await 的 ES Module,更早的版本需要改用动态 import()。

@citation-media/html-parser 需要什么版本的 Node.js?

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

@citation-media/html-parser 可以商用吗?

@citation-media/html-parser 使用 MIT 许可。宽松许可:允许商业使用、修改和再分发,通常只需在分发时保留原版权与许可声明。以上为概括,不构成法律意见,请以许可原文为准。

@citation-media/html-parser 的下载量有多少?

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

@citation-media/html-parser 还在维护吗?

最新版本 0.8.2 发布于 2026/11/04(5 天前);至今共发布 14 个版本,其中过去 12 个月发布了 14 个;首次发布于 2026/09/30。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。