npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

page-analyzer

v1.2.2

Published

Standalone page analysis module.

Readme

page-analyzer

page-analyzer 是一个独立的网页分析模块,用于抓取网页、解析 DOM、提取交互元素,并结合 OpenAI 兼容的 LLM 接口生成页面区块与事件分析结果。

它适合用于:

  • 分析页面上的链接、按钮、表单、输入框等可交互节点
  • 将页面 DOM 元素转换为结构化 CSV,便于后续分析
  • 基于视觉区块和上下文识别页面主要功能区
  • 通过 LLM 判断节点可能触发的事件类型
  • 为埋点设计、页面巡检、自动化测试或站点地图分析提供基础数据

功能概览

  • 使用 Playwright 启动 headless Chromium 抓取真实页面内容
  • 自动滚动页面并等待高度稳定,尽量覆盖懒加载内容
  • 解析 HTML 中的重要元素,包括 abuttonforminputselecttextarea、标题、图片和导航区
  • 收集元素文本、链接、表单动作、ARIA 信息、上下文文本、CSS 选择器和视觉区块位置
  • 将交互元素导出为 CSV:idx,blockIdx,tag,imageAlt,text,context,href
  • 使用 OpenAI 兼容接口进行页面区块分析和事件类型识别
  • 支持紧凑输出或完整输出,便于在不同场景控制结果体积
  • 支持高级用法:直接传入已抓取的 HTML、blocks、elementGeometries 进行分析

安装

从 npm 安装:

npm install page-analyzer

如果在本仓库内开发:

npm install

Playwright 需要可用的 Chromium。如果运行时提示浏览器缺失,可以执行:

npx playwright install chromium

环境要求

  • Node.js 20.18.1 或更高版本
  • 可访问目标网页的网络环境
  • 一个兼容 OpenAI Chat Completions 格式的 LLM 接口

快速开始

import { analyzeUrl } from 'page-analyzer';

const result = await analyzeUrl('https://example.com', {
  llm: {
    apiKey: process.env.LLM_API_KEY,
    apiEndpoint: process.env.LLM_API_ENDPOINT,
    model: process.env.LLM_MODEL
  }
});

console.log(JSON.stringify(result, null, 2));

示例 .env

LLM_API_KEY=your_api_key
LLM_API_ENDPOINT=https://api.openai.com/v1/chat/completions
LLM_MODEL=gpt-4o-mini

运行测试和示例

本地测试不会调用真实网页或 LLM 接口:

npm test

如需手动分析真实页面,可以运行示例脚本。它会读取项目根目录下的 .env,分析指定 URL,并把结果写入 result.json

npm run analyze -- https://example.com

注意:npm run analyze 依赖以下环境变量:

  • LLM_API_KEY
  • LLM_API_ENDPOINT
  • LLM_MODEL

缺少这些变量时会抛出配置错误。

API

analyzeUrl(url, options)

一站式分析入口。传入 URL 后,模块会自动完成页面抓取、HTML 解析、视觉区块提取、CSV 生成和 LLM 分析。

import { analyzeUrl } from 'page-analyzer';

const result = await analyzeUrl('https://example.com', {
  llm: {
    apiKey: 'sk-...',
    apiEndpoint: 'https://api.openai.com/v1/chat/completions',
    model: 'gpt-4o-mini',
    temperature: 0,
    maxTokens: 8000,
    timeout: 600000,
    maxRetries: 3
  },
  showEvents: true,
  showBlockIdx: true,
  fullPageScreenshot: true,
  blockScreenshots: true,
  waitForImagesLoaded: true,
  knownEventTypes: ['click_link', 'submit_form'],
  extractorConfig: {
    viewportWidth: 1440,
    viewportHeight: 900,
    timeoutMs: 30000
  },
  parserConfig: {
    contextLevel: 'full',
    maxTextLength: 200
  }
});

参数说明:

| 参数 | 类型 | 必填 | 说明 | | --- | --- | --- | --- | | url | string | 是 | 要分析的页面 URL | | options.llm.apiKey | string | 是 | LLM API key | | options.llm.apiEndpoint | string | 是 | OpenAI 兼容的 Chat Completions endpoint | | options.llm.model | string | 是 | 模型名称 | | options.llm.temperature | number | 否 | LLM 温度,默认 0 | | options.llm.maxTokens | number | 否 | 最大输出 token 数 | | options.llm.timeout | number | 否 | 单次请求超时时间,默认 600000 ms | | options.llm.maxRetries | number | 否 | LLM 请求重试次数,默认 3 | | options.llm.interactionLogger | Function | 否 | LLM 交互日志回调 | | options.knownEventTypes | string[] | 否 | 已知事件类型,用于判断新增事件类型 | | options.parserConfig | object | 否 | HTML 解析配置 | | options.extractorConfig | object | 否 | Playwright 页面抓取配置 | | options.showEvents | boolean | 否 | 是否返回完整事件数组和元素明细 | | options.showBlockIdx | boolean | 否 | 是否返回 CSV 与区块索引相关字段 | | options.fullPageScreenshot | boolean | 否 | 是否保存整页截图到当前运行目录的 snapshots/ 并返回文件路径 | | options.blockScreenshots | boolean | 否 | 是否在 LLM 合并区块后,保存每个逻辑区块截图到当前运行目录的 snapshots/ 并返回文件路径 | | options.waitForImagesLoaded | boolean | 否 | 是否在提取区块、分析和截图前等待页面图片加载完成,默认 false | | options.extractorConfig.s3 | object | 否 | 截图 S3 上传配置。配置后截图上传到 S3,返回 HTTPS URL;未配置时仍保存到本地 snapshots/ |

analyzePageEvents(input)

高级入口。适合你已经有 HTML、视觉区块或元素几何信息,不希望 page-analyzer 自己打开浏览器抓取页面的场景。

import { analyzePageEvents } from 'page-analyzer';

const result = await analyzePageEvents({
  html: '<html><head><title>Demo</title></head><body><a href="/pricing">Pricing</a></body></html>',
  url: 'https://example.com',
  blocks: [],
  elementGeometries: [],
  llm: {
    apiKey: process.env.LLM_API_KEY,
    apiEndpoint: process.env.LLM_API_ENDPOINT,
    model: process.env.LLM_MODEL
  },
  knownEventTypes: [],
  parserConfig: {
    contextLevel: 'lean'
  },
  showEvents: true,
  showBlockIdx: true,
  domain: 'example.com',
  nodeId: 'example-root'
});

主要输入:

| 字段 | 类型 | 必填 | 说明 | | --- | --- | --- | --- | | html | string | 是 | 原始 HTML | | url | string | 是 | 页面 URL,用于解析相对链接 | | blocks | Array | 否 | 视觉区块快照 | | elementGeometries | Array | 否 | 页面中交互元素的几何信息 | | llm | object | 是 | LLM 配置 | | knownEventTypes | string[] | 否 | 已知事件类型 | | parserConfig | object | 否 | HTML 解析配置 | | showEvents | boolean | 否 | 是否返回完整事件数组和元素明细 | | showBlockIdx | boolean | 否 | 是否返回 CSV 与区块索引相关字段 | | domain | string | 否 | 分析上下文中的站点域名 | | nodeId | string | 否 | 当前分析节点 ID |

如果没有传入 blocks,模块会根据 CSV 行构造 fallback block,保证 LLM 分析流程仍然可以运行。

输出结构

默认输出会保留页面标题、解析指标和紧凑后的区块分析结果:

{
  title: 'Example Domain',
  parseMetrics: {
    parseMs: 12,
    contextBuildMs: 5,
    elementsCount: 10,
    linksCount: 3,
    heapUsedMB: 28.4,
    contextLevel: 'full'
  },
  analysis: {
    block_analysis: {
      site_summary: '...',
      blocks: [
        {
          blockName: '...',
          blockDescription: '...',
          blockSemantics: [],
          blockCssPath: '...',
          blockPosition: {}
        }
      ],
      stats: {
        total_blocks: 4
      }
    }
  }
}

启用 showEvents: true 后,输出会包含更多用于调试和下游处理的字段,例如:

  • elements:解析出的页面元素明细
  • csvContent:交互元素 CSV
  • links:页面链接列表
  • analysis.events_by_node:按节点输出的事件识别结果
  • analysis.event_types_summary:事件类型汇总
  • analysis.new_event_types:不在已知类型列表中的新增事件类型
  • analysis.block_analysis.possible_event_types:页面可能存在的事件类型

启用 showBlockIdx: true 后,区块结果中会额外包含 blockIdxsblockSemanticGroupsrowCount 等字段,并返回 csvContent

启用 fullPageScreenshot: true 后,返回结果会包含 screenshots.fullPage,值为整页截图文件路径。

启用 blockScreenshots: true 后,模块会在 LLM 合并区块后再截图。返回结果会包含 screenshots.blocks,每项包含逻辑区块序号 blockIdx 和对应截图 path;区块分析结果中的每个 block 也会额外带上 blockScreenshotPaths,每个逻辑区块最多对应一张截图。无法通过 blockCssPath 截图的隐藏或空区块会被跳过。

如果配置 extractorConfig.s3,截图不会写入本地 snapshots/,而是直接上传到 S3;screenshots.fullPagescreenshots.blocks[].pathblockScreenshotPaths 会返回 HTTPS URL。S3 对象 key 使用 <prefix>/<domain>/<file-md5>.png,上传前会先检查对象是否已存在,已存在时直接返回对应 URL,避免重复上传和冗余对象。上传不会设置 ACL,访问权限沿用 bucket 策略。单张截图检查或上传失败会重试 3 次,仍失败则跳过该截图。

启用 waitForImagesLoaded: true 后,模块会先滚动页面触发懒加载,再等待当前 DOM 中的 <img> 完成加载或失败,之后再提取区块、分析和截图;等待时间受 extractorConfig.timeoutMs 控制。

截图参数启用后的新增输出示例:

{
  screenshots: {
    fullPage: '/path/to/page-analyzer/snapshots/example-com-20260507-095500-full-page.png',
    blocks: [
      {
        blockIdx: 0,
        path: '/path/to/page-analyzer/snapshots/example-com-20260507-095500-block-000.png'
      }
    ]
  }
}

配置项

extractorConfig

extractorConfig 控制 Playwright 抓取和视觉区块提取行为。

| 字段 | 默认值 | 说明 | | --- | --- | --- | | timeoutMs | 30000 | 页面导航、滚动和稳定等待超时时间 | | viewportWidth | 1440 | 浏览器视口宽度 | | viewportHeight | 900 | 浏览器视口高度 | | minBlockHeight | 40 | 最小区块高度 | | minBlockWidthRatio | 0.25 | 最小区块宽度占视口宽度比例 | | blockMaxHeightRatio | 1.5 | 最大区块高度占视口高度比例 | | blockMaxDepth | 15 | 区块提取最大 DOM 深度 | | textPreviewMaxChars | 1200 | 区块文本预览最大长度 | | waitForImagesLoaded | false | 是否在提取区块、分析和截图前等待页面图片加载完成 | | s3 | 无 | 截图 S3 上传配置。配置后截图直接上传到 S3,未配置时保存到本地 |

S3 截图上传示例:

const result = await analyzeUrl('https://example.com', {
  fullPageScreenshot: true,
  blockScreenshots: true,
  llm: {
    apiKey: process.env.LLM_API_KEY,
    apiEndpoint: process.env.LLM_API_ENDPOINT,
    model: process.env.LLM_MODEL
  },
  extractorConfig: {
    s3: {
      bucket: 'my-bucket',
      region: 'ap-northeast-1',
      prefix: 'page-analyzer/snapshots',
      publicBaseUrl: 'https://cdn.example.com',
      credentials: {
        accessKeyId: process.env.AWS_ACCESS_KEY_ID,
        secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,
        sessionToken: process.env.AWS_SESSION_TOKEN
      }
    }
  }
});

extractorConfig.s3.bucketextractorConfig.s3.region 必填。credentials 可省略,省略时使用 AWS SDK 默认凭证链。publicBaseUrl 可省略,省略时返回 https://<bucket>.s3.<region>.amazonaws.com/<key>;配置后返回 ${publicBaseUrl}/<key>。启用 S3 上传时,需要凭证具备 s3:GetObjects3:PutObject 权限;如果希望不存在的对象能被稳定识别为 404,还需要对应 bucket/prefix 的 s3:ListBucket 权限。

parserConfig

parserConfig 控制 HTML 元素解析和上下文提取行为。

| 字段 | 默认值 | 说明 | | --- | --- | --- | | importantTags | 内置标签列表 | 要提取的重要 DOM 标签 | | maxTextLength | 200 | 元素自身文本最大长度 | | maxParentTextLength | 100 | 父级文本最大长度 | | maxAncestorDepth | 5 | 祖先上下文最大深度 | | maxNearbyTexts | 5 | 附近文本最大数量 | | contextLevel | full | 上下文详细程度,可选 fulllean |

高级组件

除主 API 外,模块还导出了一些内部组件,方便按需组合:

import {
  HtmlParser,
  PageExtractor,
  CsvExporter,
  OpenAiProvider,
  BaseLlmProvider,
  EventAnalyzer,
  assignBlocksToElements
} from 'page-analyzer';

这些组件可以用于自定义分析流水线,例如只抓页面、只解析 HTML、只生成 CSV,或接入自定义 LLM provider。

LLM 接口格式

当前内置的 OpenAiProvider 会向 apiEndpoint 发送 OpenAI Chat Completions 风格请求:

{
  "model": "gpt-4o-mini",
  "messages": [
    {
      "role": "user",
      "content": "..."
    }
  ],
  "temperature": 0
}

响应中会读取:

data.choices[0].message.content

因此,只要服务兼容这一请求和响应结构,就可以作为后端 LLM 使用。

开发

安装依赖:

npm install

运行本地测试:

npm test

生成 npm 发布包预览:

npm pack --dry-run

发布前检查:

npm publish --dry-run

项目结构

page-analyzer/
  index.js                         # 模块入口,导出主 API 和高级组件
  page-extractor.js                # Playwright 页面抓取与视觉区块提取
  html-parser.js                   # HTML 解析与元素上下文提取
  csv-exporter.js                  # 交互元素 CSV 生成
  extractors/                      # 区块映射、上下文提取、选择器构建
  llm/
    providers/                     # LLM provider
    analyzers/event-analyzer/      # 页面区块和事件分析逻辑
    analyzers/prompts/             # LLM prompt 模板
    utils/                         # 事件 CSV 解析和元数据工具
  models/                          # 上下文数据模型
  utils/                           # 文本、URL、选择器工具
  vendor/                          # 浏览器内区块提取脚本
  scripts/analyze.js               # 手动真实页面分析脚本
  test/smoke.test.js               # 本地 smoke test

常见问题

npm run analyze 报 LLM 配置缺失

确认项目根目录存在 .env,并且包含:

LLM_API_KEY=your_api_key
LLM_API_ENDPOINT=https://api.openai.com/v1/chat/completions
LLM_MODEL=gpt-4o-mini

Playwright 报浏览器不存在

执行:

npx playwright install chromium

目标页面内容不完整

可以适当调大:

extractorConfig: {
  timeoutMs: 60000,
  viewportHeight: 1200
}

模块会自动滚动到底部并等待页面高度稳定,但如果目标站点需要登录、验证码、复杂交互或服务端限流,仍然可能拿不到完整内容。

LLM 返回格式解析失败

事件分析器期望 LLM 返回 CSV section。内部会尝试自动修复格式,但如果模型输出长期不稳定,可以换用更强的模型,或降低温度。

License

MIT License. See LICENSE.