页面说明生成器

SKILL效率
效率 未标注权限 许可证不明确
安装这个技能

根据用户发送的产品原型截图(可一次多张),输出标准化的「页面说明」文档。当用户发来 UI 原型/设计稿截图、要求产出页面说明、页面规格、交互说明、PRD 页面文档时使用。强制规则:同一批次截图视为同一个功能模块(不拆成多个独立页面);输出不使用 markdown 表格;遵循四段式结构(所属菜单、页面概述、功能设计描述、交互设计描述),保持简洁。

一句话选型结论

按资料字段整理

页面说明生成器是效率类的 Agent Skill,安装方式未标注,权限级别未标注,许可证不明确,有可直接复制的安装命令。技能本质是给模型读的说明书,效果取决于模型与客户端;装完先用一个小任务验证,再放进正式流程。

分类效率 安装方式未标注 权限级别未标注权限 许可证许可证不明确
累计安装 未标注 本周 未标注
GitHub 星标 未标注 仓库 未标注
下载量 未标注 技能市场下载数
权限级别 未标注权限 安装前请确认风险范围
许可证 许可证不明确 未说明

安装

未标注
在支持 Skills 的客户端里执行,装完问一句「你有哪些技能」验证
skillhub install user_0c6c8065/page-spec-generator
  1. 1
    确认客户端支持

    确认你的客户端支持 Skills(Claude、Codex、Cursor 等),并升级到较新的版本。

  2. 2
    拿到技能文件

    执行上面的命令安装;也可以把仓库里的 SKILL.md 手动放进客户端的 skills 目录。

  3. 3
    刷新技能列表

    重新打开客户端,或刷新技能列表,让新放进来的技能被加载。

  4. 4
    验证是否生效

    问一句「你有哪些技能」,确认列表里出现它,再拿一个小任务试跑。

技能档案

效率
字段来自技能仓库与公开索引,中文说明由本站标注
作者 / 维护方user_0c6c8065仓库 未标注 · 版本 未标注
宿主客户端未标注技能可被这些客户端加载
安装方式未标注安装包 community
权限级别未标注权限安装前请确认风险范围
许可证未说明许可证不明确,商用前请自行确认条款
仓库可用性available技能仓库当前是否可访问
最近核验未标注上游最后核验时间 · 数据更新 1791509162
正文体量53.4 KBSKILL.md 原文大小,越大说明说明书写得越细

典型使用场景

3 类
按分类整理的常见用法,具体以 SKILL.md 为准
整理待办与日程

把零散任务收进清单,排出优先级。

批量处理重复任务

把固定动作做成模板,重复执行。

把流程写成清单

把口头流程整理成可复用的步骤。

选择建议

装之前先看这几条
按条目字段给出的判断,不替你决定用不用

值得选的地方

  • 有可直接复制的安装命令,不用自己翻文档找入口。

先想清楚的地方

  • 没有标注权限级别,实际能做什么要装好后确认。
  • 许可证不明确,商用或二次分发前先到仓库确认条款。
  • 没有做站内核验,内容以作者仓库为准。
  • 技能只是说明书,实际效果取决于模型与客户端,装完先用小任务试一遍。

更适合

  • 需要在效率场景里给模型补一套做法的人。
  • 愿意先读一遍 SKILL.md、确认它会让模型做什么的人。

不太适合

  • 对许可证要求很严、必须明确可商用的人。
  • 只想装完就自动变强、不打算看说明书的人。

同类对比

6 个同类
同分类里挑最接近的几条,字段以各自详情页为准
技能权限级别安装方式累计安装宿主客户端安装命令
页面说明生成器当前 未标注权限 未标注 未标注 未标注 有
Nano PDF 文档 联网访问 ClawHub 市场 424.9 万 OpenClaw 有
自动更新程序 浏览器控制 ClawHub 市场 296.4 万 OpenClaw 有
Gemini 助手 联网访问 ClawHub 市场 254.7 万 OpenClaw 有
word DOCX 文档 联网访问 ClawHub 市场 239.6 万 OpenClaw 有
Excel XLSX 前端 联网访问 ClawHub 市场 227.0 万 OpenClaw 有

SKILL.md 全文

53.4 KB
模型实际读到的说明书原文,来自技能仓库

Page Spec Generator — 页面功能规格说明书生成器 (v3.3)

基于 Browser Harness (CDP 协议) 自动探索任意网站, 生成结构化、多角色可读的完整页面功能规格说明书。

> 📋 版本更新记录、规划路线图、完整代码模板见 reference.md。


适用场景

场景 说明
新项目接手 快速了解目标网站的全貌 (路由/交互/API)
竞品分析 结构化记录竞品功能模块和交互设计
回归测试基线 提供完整的交互元素目录作为测试用例基线
产品文档化 为缺乏文档的遗留系统补全前端规格
无障碍审计 自动检测 landmark/heading/alt-text 缺失

前置条件与强制约束

硬性约束

约束 说明
✅ 必须使用 Browser Harness 本 Skill 的所有浏览器操作通过 Browser Harness (CDP 协议) 执行。generate_page_spec(), page_info(), js(), capture_screenshot(), cdp() 等所有 helper 均依赖 Browser Harness
❌ 禁止使用 Playwright 除非用户明确说"用 Playwright", 否则禁止使用 Playwright/Puppeteer/Selenium 等第三方浏览器驱动。Browser Harness 直接通过 CDP 连接用户正在运行的 Chrome, 继承登录态/扩展/书签, 无需额外配置
🔧 未安装时询问用户 如果 browser-harness --doctor 失败 (command not found), 停止并询问用户是否需要自动安装。禁止未经用户许可自动执行安装命令
🚫 禁止替用户操作 Chrome 设置 当 daemon 连接失败时,引导用户自己打开 chrome://inspect/#remote-debugging 并点击 Allow。Agent 端的浏览器无法控制用户的 Chrome 设置,不要尝试替用户打开该页面

安装检查流程

执行 browser-harness --doctor
  ├── [ok] chrome running + daemon alive → 继续
  ├── [FAIL] command not found → 询问用户
  └── [FAIL] daemon/connection → 按 install.md 排查

Browser Harness 未安装时的处理

如果 browser-harness 命令不可用:

  1. 告知用户 — 说明 Browser Harness 是本 Skill 的必需依赖:
    > "Page Spec Generator 依赖 Browser Harness 进行浏览器控制。检测到你的环境中未安装 Browser Harness。"

  2. 提供安装信息 — 引用官方安装文档:
    - 安装指南: https://github.com/browser-use/browser-harness/blob/main/install.md
    - 项目说明: https://github.com/browser-use/browser-harness/blob/main/README.md

  3. 询问用户 — 使用 AskUserQuestion 工具询问:
    > "是否需要我自动安装 Browser Harness?安装命令为:
    > bash > git clone https://github.com/browser-use/browser-harness ~/Developer/browser-harness > cd ~/Developer/browser-harness > uv tool install -e . >
    > 你也可以手动执行以上命令后重新运行本 Skill。"

  4. 等待用户确认 — 仅在用户明确同意后才执行安装。禁止自动执行。

首次使用验证

在正式开始分析前,先跑 5 行验证脚本确认环境正常:

browser-harness <<'PY'
new_tab("https://www.baidu.com")
print(page_info())
PY

预期输出:

{'url': 'https://www.baidu.com/', 'title': '百度一下,你就知道',
 'w': 1536, 'h': 738, ...}
验证项 通过标志
daemon 启动 + CDP 连接 page_info() 返回 dict 非报错
页面导航 url 字段为目标 URL
JS 执行 title 字段包含中文

验证失败对照:

错误信息 原因 解决
fatal: CDP WS handshake failed Chrome 远程调试未授权 chrome://inspect 重勾 Allow
FileNotFoundError 截图目录不存在 先 mkdir -p 创建目录
Connection refused Chrome 未启动 启动 Chrome 后重试
TimeoutError 网络不通或页面太慢 换 https://www.baidu.com (国内最快)
UnicodeEncodeError Windows GBK 编码 encoding="utf-8" 写文件
Target ... not found 标签页关闭/刷新/导航到内部页后 session 失效 调用 ensure_real_tab() 重新附着到用户最后一个真实页面

验证通过后即可开始 Phase 0 全站分析。

其他前置条件

  • Chrome 浏览器已启动,两种方式任选其一:
  • Way 1 (推荐): chrome://inspect/#remote-debugging 勾选 Allow — 继承日常登录态,适合大多数场景
  • Way 2 (无人值守/反自动化站点): 启动 Chrome 时加 --remote-debugging-port=9222 --user-data-dir=<非默认路径>,然后 export BU_CDP_URL=http://127.0.0.1:9222。Windows 示例:
    bash "C:\Program Files\Google\Chrome\Application\chrome.exe" --remote-debugging-port=9222 --user-data-dir=C:\temp\chrome-dev
  • agent_helpers.py 已加载 (含 page_*() 函数, Browser Harness 安装后自动可用)
  • (可选) BROWSER_USE_API_KEY 环境变量 — 仅云端浏览器需要

方法论 / 8 阶段流水线

Phase 0 ── 初始扫描 (generate_page_spec)
     │
Phase 1 ── 导航爬取 (page_nav_all_links)
     │
Phase 2 ── 穷举交互 (逐个点击/输入/切换 + 行为推理 + 弹窗递归 + 缺口标记)
     │
Phase 3 ── API 监控 (Performance API + fetch 包装器)
     │
Phase 4 ── 状态机测试 (登录/错误/空/加载态 + 会话管理)
     │
Phase 5 ── 响应式检查 (多断点 + CDP 仿真)
     │
Phase 6 ── 编译文档 (14+ 章节 + 截图规范 + 缺口清单)

分析模式选择

本 Skill 支持两种分析模式, 根据用户意图自动选择:

用户输入 URL + 分析需求
  │
  ├── 用户指定了具体模块 (如"分析酒店的搜索功能")
  │     → 🔬 模块深度分析模式 (§M)
  │
  ├── 用户说"全站"/"整个网站"/未指定模块
  │     → 🌐 全站分析模式 (§0-7)
  │     → 先执行 Phase 0 全站扫描
  │     → 展示模块列表
  │     → 询问用户: "发现 N 个功能模块, 是否需要针对某个模块深度分析?"
  │
  └── 用户说"先全站再深入某个模块"
        → 🌐 全站分析 → 产出全景文档
        → 🔬 再对指定模块执行深度分析
模式 适用场景 深度 产出章节
🌐 全站分析 (§0-7) 新项目接手、竞品全貌、快速了解 广度优先 14+ 章
🔬 模块深度分析 (§M) 深入某个功能、测试用例基线、分支覆盖 深度优先 8 章 (每章更密集)

建议策略: 先用全站模式获得全景图, 再对核心模块逐一深度分析。模块分析结果可合并到全站文档中作为独立章节。



Phase 0 — 站点分类与初始扫描

0.1 站点类型分类

在开始扫描前, 先判断站点类型以调整分析深度:

def classify_site(url):
    """根据 URL 和首页内容推断站点类型。"""
    goto_url(url)
    time.sleep(3)
    title = (js("document.title") or "").lower()
    body = (js("document.body.innerText") or "").lower()[:500]

    if any(kw in title for kw in ["docs", "documentation", "指南", "api", "reference"]):
        return "documentation"   # 文档站: 侧重导航/搜索/侧栏目录
    if any(kw in title for kw in ["market", "skill", "shop", "store"]):
        return "marketplace"     # 市场/电商: 侧重分类/筛选/搜索/支付
    if any(kw in title for kw in ["community", "forum", "blog", "技术", "开发者"]):
        return "community"       # 社区: 侧重内容流/评论/认证/广告
    if any(kw in title for kw in ["admin", "dashboard", "console", "管理"]):
        return "saas"            # SaaS: 侧重数据表格/CRUD/权限
    return "portal"              # 门户: 综合, 按默认深度分析

各类型分析侧重点:

类型 侧重模块 跳过/轻量
documentation 导航层级, 搜索类型(本地/Algolia), 侧栏目录, API 列表 广告分析, 登录态
marketplace 分类页, 筛选/排序, 搜索, 商品列表 用户中心, 后台
community 内容流(无限滚动), 评论, 认证, 广告密度 支付流, 后台管理
saas 数据表格, 表单验证, 权限, CRUD 首页营销内容
portal 全量分析, 均衡覆盖 无跳过

0.2 初始扫描

# 基础扫描
result = generate_page_spec(
    "https://target-site.com",
    scroll_pause=1.5,
    scroll_steps=5,
    explore_tabs=True,
    deep=True,
)
summary = result.get('summary', {})
spec_path = summary.get('spec_file')

> ⚠️ SPA 兼容性警告: generate_page_spec() 内部使用 CDP Input.dispatchMouseEvent (mouseWheel) 实现滚动。这是 Chromium 已知 Bug (crbug.com/444929150) — SPA / 重 JS 页面 / Docker 环境下 CDP wheel 事件可能超时。Puppeteer #13317 和 Playwright #1115 均有相同问题。

> 降级方案: 如果 generate_page_spec() 超时,跳过滚动,改用 JS 原生滚动 + 手动采集:
> python > # 检测页面是否 SPA (page_height ≈ viewport_height) > info = page_info() > if info.get("ph", 0) <= info.get("h", 900): > # SPA: 用 window.scrollBy 替代 CDP mouseWheel > wait_for_network_idle(timeout=15, idle_ms=1500) > time.sleep(5) > for _ in range(5): > js("window.scrollBy(0, 300)") > time.sleep(1.5) > js("window.scrollTo(0, 0)") > > # 手动执行 generate_page_spec 内部的采集函数 > elements = page_interactive_elements() > structure = page_semantic_structure() > forms = page_forms() > media = page_media() > # 这些函数不依赖滚动,SPA 上已验证可用 >

0.3 输出文件管理

generate_page_spec() 的输出文件可能位于 temp 目录。必须将其移至项目目录:

import pathlib, shutil

spec_path = summary.get('spec_file')
if spec_path and pathlib.Path(spec_path).exists():
    target_dir = pathlib.Path("agent-workspace/domain-skills/page-exploration")
    target_dir.mkdir(parents=True, exist_ok=True)

    target_file = target_dir / f"page-spec-{hostname}.md"
    shutil.copy2(spec_path, target_file)
    print(f"Spec relocated: {spec_path} → {target_file}")

Phase 1 — 导航爬取与路由全景

1.1 枚举所有导航链接

nav = json.loads(js("""
(function(){
    var items = [];
    var seen = new Set();
    document.querySelectorAll('a[href]').forEach(function(a){
        var text = (a.innerText || a.textContent || '').trim();
        if (!text || text.length > 40) return;
        var href = a.getAttribute('href') || '';
        if (!href || href === '#' || href.startsWith('javascript:')) return;
        var key = text + '|' + href;
        if (seen.has(key)) return; seen.add(key);
        items.push({text: text.slice(0,35), href: href.slice(0,120)});
    });
    return JSON.stringify(items);
})();
"""))

1.2 URL 归一化

import re
from urllib.parse import urlparse, urljoin

def normalize_url(href, base_domain):
    """归一化 URL: 提取 path 部分, 处理子域名和 CDN。"""
    if href.startswith(('mailto:', 'tel:', 'javascript:')):
        return None
    if href.startswith('/'):
        return href.split('?')[0].split('#')[0]
    if href.startswith(('http://', 'https://', '//')):
        parsed = urlparse(href if '//' in href else 'https:' + href)
        host = parsed.hostname or ''
        if host.endswith('.' + base_domain) or host == base_domain:
            return parsed.path.split('?')[0].split('#')[0] or '/'
        else:
            return 'external'
    if not href.startswith(('http', '//')):
        return href.split('?')[0].split('#')[0]
    return None

1.3 分类、去重与广告检测

from collections import defaultdict

internal = []
external = []
ad_links = []
ad_keywords = ['ad', 'ads', 'promo', 'sponsor', 'click', 'track', 'utm_', 'banner']

for n in nav:
    href = n['href']
    path = normalize_url(href, base_domain)
    if path is None:
        continue
    if path == 'external':
        is_ad = any(kw in href.lower() for kw in ad_keywords)
        if is_ad:
            ad_links.append(n)
        else:
            external.append(n)
    else:
        n['_path'] = path
        internal.append(n)

by_prefix = defaultdict(list)
for n in internal:
    p = n['_path']
    prefix = p.split('/')[1] if p.count('/') > 1 else 'root'
    by_prefix[prefix].append(n)

print(f"Internal: {len(internal)}, External: {len(external)}, Ad/Track: {len(ad_links)}")

1.4 SPA 路由枚举

对于多域名 SPA 架构, 手动枚举子域名:

subdomains = set()
for n in internal:
    for match in ['live.', 'search.', 'space.', 'member.', 'show.', 'manga.']:
        if match in n['href']:
            subdomains.add(match.rstrip('.'))

for sub in subdomains:
    generate_page_spec(f"https://{sub}.target.com")

Phase 2 — 深度交互分析

> 核心原则: 页面上每一个可操作元素, 都必须被操作一次, 观察反应, 记录行为。不是"知道有什么元素", 而是"每个元素点了之后会发生什么"。

交互策略

  1. 枚举所有可交互元素 — 使用综合选择器覆盖: 标准 HTML 元素 + ARIA role + 常见交互 class 模式。跳过不可见元素 (display:none / 0×0 尺寸),去重用 tag+text+class+rect 联合键
  2. 逐个执行交互 — 每种元素类型用对应操作: button/link→click、input/textarea→输入测试值、select→切换选项、checkbox/radio→toggle、slider→模拟拖动
  3. 记录操作前后状态 — 截图 + DOM hash + URL 对比,判断效果 (导航/弹窗/DOM变化/无变化)
  4. 恢复状态 — 弹窗尽量关闭 (Escape+关闭按钮)、toggle 再次点击还原、页面导航用 go_back
  5. 递归弹窗 — 弹窗/下拉面板内的元素纳入下一轮交互,max_depth=3

> 📝 完整 JS 选择器代码、交互执行器、效果分类函数见 reference.md §Phase 2。

2.2 交互元素目录分类

对每个关键页面, 枚举所有可交互元素 (作为穷举交互的补充信息目录):

def analyze_page_interactions(url):
    """返回页面上所有按钮/输入框/链接/Tab/表单/开关的详细目录。"""
    # 穷举交互已经包含了元素发现, 此函数仅作结构化分类供文档引用
    goto_url(url)
    time.sleep(4)
    wait_for_load()
    wait_for_network_idle(timeout=12.0, idle_ms=1000)

    auth = detect_auth_forms()

    catalog = json.loads(js("""
    (function(){
        var items = {buttons:[], inputs:[], links:[], tabs:[], forms:[], toggles:[]};
        var seen = new Set();

        document.querySelectorAll('button, [role="button"], [class*="btn"], [class*="button"]').forEach(function(el){
            var text = (el.innerText || el.textContent || '').trim().replace(/\\s+/g,' ').slice(0,40);
            if (!text || seen.has('btn_'+text)) return; seen.add('btn_'+text);
            items.buttons.push({
                text: text, tag: el.tagName, cls: (el.className||'').slice(0,60),
                disabled: el.hasAttribute('disabled'),
                href: (el.getAttribute('href')||'').slice(0,60)
            });
        });

        document.querySelectorAll('input:not([type=hidden]):not([type=submit]), textarea, select').forEach(function(el){
            var type = el.getAttribute('type')||el.tagName;
            items.inputs.push({
                type: type,
                isPassword: type === 'password',
                placeholder: (el.getAttribute('placeholder')||'').slice(0,40),
                name: el.getAttribute('name')||'',
                maxlength: el.getAttribute('maxlength')||'',
                minlength: el.getAttribute('minlength')||'',
                required: el.hasAttribute('required'),
                pattern: (el.getAttribute('pattern')||'').slice(0,60),
                readonly: el.hasAttribute('readonly')
            });
        });

        document.querySelectorAll('a[href]:not([href="#"]):not([href^="javascript:"])').forEach(function(a){
            var text = (a.innerText||a.textContent||'').trim().replace(/\\s+/g,' ').slice(0,50);
            var href = a.getAttribute('href')||'';
            if (!text || text.length > 40) return;
            items.links.push({text: text, href: href.slice(0,100), target: a.getAttribute('target')||''});
        });

        var tabCandidates = document.querySelectorAll(
            '[role="tab"], [class*="tab"]:not(a):not(button):not([class*="table"]), ' +
            'button[class*="tab"], a[class*="tab"], ' +
            '[class*="sort"], [class*="filter"], [class*="category"]'
        );
        tabCandidates.forEach(function(el){
            var text = (el.innerText||el.textContent||'').trim();
            if (!text || text.length > 25) return;
            if (/^\\d+$/.test(text.trim()) && parseInt(text) < 100) return;
            items.tabs.push({
                text: text,
                badge: text.match(/\\d+/)?.[0] || '',
                active: el.classList.contains('active')||el.getAttribute('aria-selected')==='true'
            });
        });

        document.querySelectorAll('form').forEach(function(f){
            items.forms.push({
                action: (f.getAttribute('action')||'').slice(0,60),
                method: f.getAttribute('method')||'get',
                inputs: f.querySelectorAll('input,textarea,select').length,
                hasSubmit: !!f.querySelector('button,[type="submit"]'),
                hasPassword: !!f.querySelector('input[type="password"]')
            });
        });

        return JSON.stringify(items);
    })();
    """))

    catalog['_auth'] = auth
    return catalog


def detect_auth_forms():
    auth = json.loads(js("""
    (function(){
        var result = {hasLoginForm: false, hasPassword: false, hasCaptcha: false};
        var inputs = document.querySelectorAll('input[type="password"]');
        if (inputs.length > 0) {
            result.hasPassword = true;
            result.hasLoginForm = true;
        }
        if (document.querySelector('img[src*="captcha"], [class*="captcha"], [id*="captcha"]')) {
            result.hasCaptcha = true;
        }
        return JSON.stringify(result);
    })();
    """))
    return auth

2.3 行为规格描述规则

对每个元素类型, 在文档中记录以下内容:

元素类型 必记录字段
按钮 文本、CSS class、disabled 状态、href/onclick、点击行为(页面跳转/弹窗/状态切换)、再次点击同一按钮的效果(幂等/取消/无操作)
输入框 placeholder、type、maxlength、minlength、required、pattern(正则)、readonly、Enter 触发行为、防抖延迟(若有)
链接 文本、href、target、所属分类(导航/内容/功能)、是否通过重定向 URL
Tab 文本、active 状态、切换后内容变化、切换后页码重置行为、点击已选中 Tab 的行为
表单 action、method、input 数量、submit 按钮、验证规则、隐私协议勾选
开关/复选 checked 状态、label、切换效果
统计徽标 是否可点击(display-only vs clickable filter)、点击后与其他筛选的组合规则
分类筛选 单选/多选、取消选中方式、全部清除入口

2.4 搜索深度分析

搜索是文档站/市场的核心功能, 需区分两种类型:

类型 A: 本地索引搜索

  • 搜索索引在构建时生成, 离线仍可用
  • 无网络请求, 纯客户端过滤
  • 适用于 SSG 静态文档站

类型 B: 云搜索 (如 Algolia DocSearch)

  • 每次查询实时请求云 API
  • 离线不可用
  • 需收集: appId, apiKey, indexName, facetFilters, placeholder
  • 需检查: 快捷键(Ctrl+K/Cmd+K)、键盘导航(↑↓→Enter/Esc)、结果分组、摘要长度、缺失结果链接

搜索行为验证清单

def analyze_search_behavior(url):
    """分析搜索行为: 触发方式、防抖、结果展示、边界条件。"""
    # 1. 判断搜索类型: 本地 vs 云
    search_type = "local"  # 默认假设
    algolia_config = json.loads(js("""
    (function(){
        // 检查 Algolia DocSearch
        var ds = window.docsearch || window.__DOCSEARCH__;
        if (ds) return JSON.stringify({type:'algolia', config: ds});
        // 检查 localStorage 中的 DocSearch 键
        var keys = Object.keys(localStorage).filter(k => k.includes('DOCSEARCH'));
        if (keys.length > 0) return JSON.stringify({type:'algolia', lsKeys: keys});
        return JSON.stringify({type:'local'});
    })();
    """))

    # 2. 测试触发方式: Enter vs 实时防抖
    # 在网络面板打开的情况下, 在搜索框逐字输入, 观察 API 请求
    # 若有递增的搜索请求 → 实时防抖; 仅 Enter 时触发 → 手动触发

    # 3. 边界条件
    return {
        "search_type": search_type,
        "config": algolia_config,
        "gaps": [
            "搜索触发方式: Enter-only vs 实时防抖? 需实机验证",
            "搜索结果为空时: 显示什么? 引导文案?",
            "搜索特殊字符 (<script> 等) 的 XSS 防护表现",
            "搜索输入是否有 min/max 字符限制?",
            "搜索历史/自动补全是否存在?"
        ]
    }

2.5 行为缺口标记 (Gap Marking)

在编写每个交互元素的行为描述时, 对不确定的交互标记 Gap:

格式: ⚠️ Gap: {描述} — 需实机验证 {具体操作}

示例:
- ⚠️ Gap: 再次点击已选中的 Tab 是否触发重复请求? 还是被前端幂等拦截?
- ⚠️ Gap: 搜索是回车触发还是基于防抖的实时搜索? 
- ⚠️ Gap: 分类筛选是否支持 Ctrl+点击多选?
- ⚠️ Gap: 快速切换 Tab 时是否存在竞态条件?

Gap 优先级定义:
| 级别 | 说明 | 行动要求 |
|------|------|----------|
| P0 | 核心行为冲突 (文档断言 vs 实际行为矛盾) | 立即实机验证并修正文档 |
| P1 | 行为未验证但关键 (影响功能完整性理解) | 安排实机验证 |
| P2 | 细节确认 (加载态样式、滚动位置、动画) | 可选验证 |


Phase 3 — API 数据流监控

采集策略

  1. Performance API 快速扫 — performance.getEntriesByType('resource') 提取 API URL 列表,过滤静态资源。⚠️ 只捕获页面加载后的请求
  2. 三步深度采集 — (1) 提取真实 URL+查询参数 (2) 浏览器内 fetch() 携带 Cookie 获取响应体 (3) 校验错误反向推断 POST 入参格式
  3. 关键教训: js() 大返回值分步采集、http_get() 不带 Cookie 必须用浏览器内 fetch、POST 端点靠 ValidationError 推断参数、每次 fetch 后 time.sleep(0.5) 防反爬
  4. 校验错误解读: "xxx should not be empty"→必填缺失 / "must be one of: A,B,C"→枚举不合法 / "must be a number"→类型错误 / "Request head is null"→需认证

API 文档格式

每个端点文档必须包含: 完整 URL、HTTP 方法、触发时机与行为、调用方模块、认证要求、请求参数表、响应 JSON、响应字段说明表、错误码与解决方法。

> 📝 完整三步法代码、OpenAPI Schema 生成、校验错误推断示例见 reference.md §Phase 3。


Phase 4 — 状态机测试

测试场景

场景 测试 URL 检查点
404 路由 /nonexistent-page 标题含"404"? 导航保留? 搜索可用? 友好消息? 推广内容?
空搜索 ?keyword=__empty__ 0 结果 Tab
未登录受限 /history (无登录) 登录拦截 / 空数据
无效 ID /resource/INVALID 错误提示 / 空状态

登录状态机

从 JS 源码提取错误码分支: 搜索页面文本中的 "10\d{2}" / "12\d{2}" 模式,常见: 1042(冻结)、1232(异地限流)、1236(验证码)、1068(二次认证)。

会话管理

收集 Cookie 中的认证键 (CASTGC, UserName, AU, access-token 等) 和 localStorage 中的 token/login/auth/session 键。

内容流

检测加载指示器 (spinner/skeleton/load-more),推断批量大小和结束态。

权限矩阵

按未登录→已登录→VIP→超级VIP 四级记录功能差异。

> 📝 完整代码模板 (404检测、登录错误码、会话分析、无限滚动、图片密度) 见 reference.md §Phase 4。


Phase 5 — 响应式断点

断点 常见行为
768px 侧栏切换点: ≥768 可见, <768 汉堡菜单
1280px 宽屏大纲/粘性导航生效
1024px 列数切换
  • JS 赋值的 window.innerWidth= 在现代 SPA 中不触发真正的 CSS 媒体查询重排
  • 推荐用 CDP Emulation: cdp(&quot;Emulation.setDeviceMetricsOverride&quot;, width=768, height=1024, deviceScaleFactor=2, mobile=True)

> 📝 完整响应式检查代码见 reference.md §Phase 5。


Phase 6 — 编译文档

截图规范

所有 Phase 中采集的截图统一按以下规范管理:

SHOTS = pathlib.Path(&quot;agent-workspace/domain-skills/page-exploration/screenshots-{site}&quot;)
SHOTS.mkdir(parents=True, exist_ok=True)

def screenshot_page(name, url):
    goto_url(url)
    time.sleep(4)
    wait_for_load()
    wait_for_network_idle(timeout=10.0, idle_ms=1000)
    shot_path = str(SHOTS / f&quot;{name}.png&quot;)
    capture_screenshot(path=shot_path)
    return shot_path

截图命名规则: {module}_{state}.png
- home.png — 首页默认态
- search.png — 搜索结果页
- login_modal.png — 登录模态框
- error_404.png — 404 错误页
- empty_state.png — 空状态

7.1 文档结构模板 (14+ 章)

# 页面功能规格说明书 — {站点名称}

- 版本: 3.x (行为规格版)
- 目标站点: {URL}
- **站点类型**: {documentation/marketplace/community/saas/portal}
- **适用对象**: 前端开发 · 后端开发 · 测试/QA · 产品经理 · 部门领导
- **分析基础**: {数据来源描述, 如 &quot;基于 Browser Harness 采集 + Agent 团队行为分析&quot;}

## 目录
1. [功能模块 A](#1-功能模块A)
2. [功能模块 B](#2-功能模块B)
...
N. [全局搜索](#N-全局搜索) (区分本地/云端)
N+1. [用户认证与状态机](#N+1-用户认证)
N+2. [会话管理](#N+2-会话管理)
N+3. [权限边界矩阵](#N+3-权限边界矩阵)
N+4. [输入验证规则汇总](#N+4-输入验证)
N+5. [API 数据流与网络请求](#N+5-api-数据流)
N+6. [键盘快捷键与无障碍](#N+6-键盘快捷键)
N+7. [响应式设计与断点](#N+7-响应式设计)
N+8. [行为缺口清单](#N+8-行为缺口清单)
N+9. [架构总览与技术债评估](#N+9-架构评估)

### 各章节内容规范:

## {N}. 用户认证与状态机

### 状态流转图 (含错误码分支)

状态: logged_out → logging_in → verification_required → logged_in
→ remote_login_verify → sign_page
→ frozen (1042)
→ rate_limited (1232)
→ captcha_required (1236/1237)

迁移条件:
logged_out → 点击登录 → logging_in (模态框弹出)
logging_in → 提交凭据 → API 调用
├── 成功 → logged_in (模态框关闭, 导航更新)
├── 1042 → 显示 "账号已被冻结"
├── 1232 → 显示 "异地登录限制, 今日禁止"
├── 1233 → redirect to /sign (异地验证)
├── 1236/1237 → verification_required (验证码输入)
└── 网络错误 → 显示 "网络异常, 请重试"


### 验证规则表
| 字段 | 类型 | 必填 | pattern | 前端阻断条件 |
|------|------|------|---------|-------------|
| 账号 | text/email | 是 | 无 | 空时按钮 disabled |
| 密码 | password | 是 | 无 | 空时按钮 disabled |
| 隐私协议 | checkbox | 是 | — | 未勾选时阻止提交 |

### 会话管理
| 机制 | 详情 |
|------|------|
| Cookie | CASTGC, UserName, AU, access-token 等 |
| localStorage | loginType, loginSuccess, sourceFrom |
| Token 交换 | POST /v1/login/exchange/ticket |
| 自动登录 | Cookie 自动恢复会话 |
| 过期行为 | API 401 → 清除登录态 → 导航恢复未登录 |

## {N+5}. API 数据流与网络请求 (v3.1 增强)

&gt; **编写原则**: 每个 API 端点必须包含&quot;前端如何调用、何时调用、入参是什么、返回值是什么&quot;四个要素。禁止只列 URL 和用途。参考 §3.5 的三步采集法获取完整数据。

### API 全景表

| # | API 端点 | 方法 | 服务号 | 触发时机 | 认证 |
|---|----------|------|--------|----------|------|

### {API-1 名称} (HTTP 方法)

| 属性 | 详情 |
|------|------|
| **完整 URL** | https://m.{host}/restapi/soa2/{serviceId}/{path} |
| **HTTP 方法** | GET / POST |
| **Content-Type** | application/json (POST) |
| **触发时机** | 页面加载时 / 用户点击 {按钮} 时 / 输入搜索词时 |
| **触发行为** | 具体描述: 用户做了什么动作导致此 API 被调用 |
| **调用方** | 哪个 MFE 模块 / React 组件 / 事件处理函数 |
| **认证要求** | 无需 / 需要 {cookieName} Cookie / 需要 Bearer Token |
| **查询参数** | _fxpcqlniredt (去重), x-traceID (链路追踪) — 自动携带 |

**前端调用方式** (实际 JS 代码):
\`\`\`javascript
fetch(&#x27;https://m.{host}/restapi/soa2/{id}/{path}&#x27;, {
    method: &#x27;POST&#x27;,
    credentials: &#x27;include&#x27;,
    headers: { &#x27;Content-Type&#x27;: &#x27;application/json&#x27; },
    body: JSON.stringify({
        // 实际请求参数
    })
})
\`\`\`

**请求参数**:
| 参数 | 类型 | 必填 | 说明 |
|------|------|------|------|
| param1 | string | ✅ | 说明 |
| param2 | int | ❌ | 说明 (默认值) |

**响应体** (实际捕获, 截断至 3000 字符):
\`\`\`json
{ &quot;ResponseStatus&quot;: {...}, &quot;data&quot;: {...} }
\`\`\`

**响应字段说明**:
| 字段 | 类型 | 说明 |
|------|------|------|
| ResponseStatus.Ack | string | &quot;Success&quot; / &quot;Failure&quot; |
| data.xxx | type | 说明 |

**错误码** (从实际响应提取):
| 错误 | 原因 | 解决方案 |
|------|------|----------|
| resultCode: -1, resultMsg: &quot;Cver error&quot; | 缺少客户端版本号 | body 中补充 cver 字段 |
| returnCode: &quot;6&quot;, returnMsg: &quot;appId is Empty&quot; | 缺少 appId 参数 | 查询参数中补充 appId= |

### API 通用模式

**请求规范**:
- 所有 API 自动携带 Cookie (\`credentials: &#x27;include&#x27;\`)
- 链路追踪: \`_fxpcqlniredt\` + \`x-traceID\` 查询参数
- POST 统一 \`Content-Type: application/json\`
- 平台标识通过 \`head.platform\` / \`head.group\` 区分

**响应规范**:
- 统一信封: \`{ ResponseStatus: { Ack, Errors[], Extension[] } }\`
- 错误分类: \`FrameworkError\` (系统), \`ValidationError\` (校验), \`AuthException\` (认证)
- 时间戳: Microsoft JSON Date (\`/Date(UnixTimestampMs+Offset)/\`)
- 全链路追踪: \`CLOGGING_TRACE_ID\` + \`RootMessageId\` + \`XRequestId\`

## {N+1}. 行为缺口清单

| 编号 | 模块 | 缺口描述 | 优先级 | 涉及章节 |
|------|------|----------|--------|----------|
| GAP-01 | 搜索 | 触发方式不确定: Enter-only vs 实时防抖? | P0 (冲突) | §2 |
| GAP-02 | 筛选 | 是否支持 Ctrl+点击多选? | P1 (关键) | §3 |
| GAP-03 | 分页 | 分页状态是否同步到 URL? 刷新后保持? | P1 (关键) | §2 |
| GAP-04 | 搜索 | XSS 注入 `&lt;script&gt;alert(1)&lt;/script&gt;` 表现 | P1 (安全) | §4 |
| GAP-05 | 加载 | 加载指示器具体形态 (骨架屏 vs Spinner) | P2 (细节) | §2 |

7.2 导航流图生成 (v3.1 新增)

在文档开头生成 Mermaid 导航流图, 可视化页面间流转关系:

def generate_navigation_flow(hostname, internal_links):
    &quot;&quot;&quot;生成 Mermaid 流程图的 Markdown 代码。&quot;&quot;&quot;
    import json

    # 按前缀分组组织节点
    groups = {}
    for link in internal_links:
        path = link.get(&#x27;_path&#x27;, &#x27;/&#x27;)
        prefix = path.split(&#x27;/&#x27;)[1] if path.count(&#x27;/&#x27;) &gt; 1 else &#x27;root&#x27;
        if prefix not in groups:
            groups[prefix] = []
        groups[prefix].append(link[&#x27;text&#x27;])

    mermaid_lines = [&quot;```mermaid&quot;, &quot;graph TD&quot;]
    seen = set()

    # 首页作为起点
    mermaid_lines.append(f&quot;  Home[\&quot;首页 /\&quot;])&quot;)
    seen.add(&#x27;root&#x27;)

    # 为每个分组生成子图
    for prefix, links in sorted(groups.items()):
        if prefix not in seen:
            mermaid_lines.append(f&quot;  subgraph {prefix}&quot;)
            for link_text in links[:8]:  # 每分组最多 8 个
                safe_text = link_text.replace(&#x27;&quot;&#x27;, &quot;&#x27;&quot;)
                mermaid_lines.append(f&quot;    {prefix}_{hash(link_text)%1000}[{safe_text}]&quot;)
            mermaid_lines.append(&quot;  end&quot;)
            seen.add(prefix)
            # 连线: Home → 分组
            mermaid_lines.append(f&quot;  Home --&gt; {prefix}&quot;)

    mermaid_lines.append(&quot;```&quot;)
    return &quot;\n&quot;.join(mermaid_lines)

输出示例:

graph TD
  Home[&quot;首页 /&quot;]
  subgraph usage
    usage_42[用量信息]
  end
  subgraph api_keys
    api_keys_7[API Keys]
  end
  subgraph top_up
    top_up_91[充值]
  end
  Home --&gt; usage
  Home --&gt; api_keys
  Home --&gt; top_up

对于更复杂的跨页面流程 (如登录 → 首页 → 功能页), 生成全站级导航流图:

def generate_site_flow():
    &quot;&quot;&quot;生成全站级导航流程 Mermaid 图。&quot;&quot;&quot;
    return &quot;&quot;&quot;```mermaid
flowchart TD
    A[&quot;首页 /&quot;] --&gt; B[&quot;登录页 /login&quot;]
    A --&gt; C[&quot;功能页 /features&quot;]
    B --&gt; D{&quot;认证成功?&quot;}
    D --&gt;|是| E[&quot;工作台 /dashboard&quot;]
    D --&gt;|否| B
    E --&gt; F[&quot;个人设置 /profile&quot;]
    E --&gt; G[&quot;数据管理 /data&quot;]
    E --&gt; H[&quot;退出登录&quot;]
    H --&gt; A
```&quot;&quot;&quot;

流图放置位置: 在文档 ## 1. 功能总览 章节之后立即插入, 作为"页面导航全景图"。

7.3 组件状态模型 (v3.1 新增)

每个交互元素需记录完整状态矩阵, 而非仅默认态:

### {组件名} 状态矩阵

| 状态 | 视觉表现 | 行为 |
|------|----------|------|
| **default** | 正常显示 | 可点击/可交互 |
| **hover** | 背景色变化 / 下划线 | - |
| **focus-visible** | outline / 边框高亮 | 键盘 Tab 可到达 |
| **active/pressed** | 缩放/颜色加深 | 触发动作 |
| **disabled** | 灰色 / 低透明度 | 点击无响应, cursor: not-allowed |
| **loading** | Spinner / 骨架屏 | 用户不可重复点击 |
| **error** | 红色边框 / 错误提示 | 显示验证失败信息 |
| **empty** | 占位符 / 空态插画 | 引导用户操作 |
| **selected** | 高亮 / 勾选图标 | 表示当前选项 |

示例 — 搜索输入框状态矩阵:

## 搜索输入框 (search-input)

| 状态 | 视觉 | 行为 |
|------|------|------|
| default | placeholder=&quot;搜索...&quot; | 等待输入 |
| focus | 边框蓝色 1px | 键盘输入, 防抖 300ms 后触发搜索 |
| typing | 显示清除按钮(×) | 实时搜索建议下拉 |
| empty-input | 显示搜索图标 | 搜索按钮 disabled |
| loading | 右侧 Spinner | 请求进行中, 防抖重置 |
| error | 红色边框 + Toast | 网络错误提示 |
| results-shown | 下拉结果面板 | ↑↓ 导航, Enter 选中 |
| no-results | 面板显示&quot;未找到相关结果&quot; | 引导修改关键词 |

记录要求:
- 每个组件类型至少记录 4 种状态 (default / disabled / loading / error)
- 交互式组件 (按钮/输入/切换) 需覆盖所有适用状态
- 状态迁移条件需用自然语言描述

7.4 无障碍深度报告模板 (v3.1 新增)

除基础的 landmark/heading 检测外, 扩展为完整的 WCAG 合规检查:

## 无障碍评估报告

### 1. 键盘可访问性
| 检查项 | 结果 | 严重度 |
|--------|------|--------|
| Tab 顺序是否合理 (visual order = DOM order) | ❌/✅ | 高 |
| 焦点指示器是否可见 (outline 未被 `:focus { outline: none }` 清除) | ❌/✅ | 高 |
| Escape 键是否关闭弹窗/下拉/模态框 | ❌/✅ | 高 |
| 模态框打开时是否焦点陷阱 (Tab 循环在框内) | ❌/✅ | 高 |
| 长页面是否有&quot;跳过导航&quot;链接 (Skip to Content) | ❌/✅ | 中 |
| 自定义组件 (滑条/树/网格) 是否支持箭头键导航 | ❌/✅ | 中 |

### 2. ARIA 使用检查
| 检查项 | 结果 | 严重度 |
|--------|------|--------|
| 动态内容区域使用 aria-live (polite/assertive) | ❌/✅ | 高 |
| aria-expanded 与展开状态同步 | ❌/✅ | 中 |
| aria-current 标记当前导航项 | ❌/✅ | 中 |
| aria-label 覆盖无文字图标的按钮 | ❌/✅ | 高 |
| role=&quot;alert&quot; 用于错误消息 | ❌/✅ | 中 |

### 3. 色彩与对比度
| 检查项 | 结果 |
|--------|------|
| 正文文本对比度 ≥ 4.5:1 (AA) / ≥ 7:1 (AAA) | ❌/✅ |
| 大号文本 (≥18px bold / ≥24px) 对比度 ≥ 3:1 | ❌/✅ |
| 非文本元素 (图标/边框) 对比度 ≥ 3:1 | ❌/✅ |
| 焦点指示器对比度 ≥ 3:1 | ❌/✅ |
| 链接颜色与周围文本的区别 (不仅是颜色) | ❌/✅ |

### 4. 屏幕阅读器
| 检查项 | 结果 |
|--------|------|
| 页面标题 (`&lt;title&gt;`) 是否描述当前页面内容 | ❌/✅ |
| 标题层级 (`&lt;h1&gt;-&lt;h6&gt;`) 是否合理嵌套 | ❌/✅ |
| 图片 alt 文本缺失数 | N |
| aria-hidden 是否误用于可交互元素 | ❌/✅ |
| 表单输入是否有关联 `&lt;label&gt;` | ❌/✅ |
| 错误消息是否通过 aria-describedby 关联到输入框 | ❌/✅ |

### 5. 触控目标 (移动端)
| 检查项 | 标准 | 结果 |
|--------|------|------|
| 所有交互目标 ≥ 44×44px (WCAG 2.5.8) | ≥44px | ✅/❌ |
| 相邻目标间距 ≥ 8px | ≥8px | ✅/❌ |

7.5 文档编写原则

  1. 聚焦行为, 而非结构: 重点写"点击按钮后会发生什么(分支 A/B/C)", 而非"有一个按钮"
  2. 标记不确定性: 所有推测行为添加 ⚠️ Gap: 前缀
  3. 保留矛盾证据: 如果文档 v2.0 断言 A 但新证据指向 B, 标记冲突而非单方面覆盖
  4. 自然语言叙述: 流程图 + 段落描述, 避免纯表格罗列
  5. 多角色可读: 前端团队看到技术细节, 产品/测试看到行为分支

7.6 文档质量检查清单

检查项 标准
穷举交互覆盖率 每个可交互元素都被操作过(点击/输入/切换), 非仅枚举
按钮规格 每个按钮: 文本/class/disabled/click 行为/幂等性/点击效果
输入框规格 每个输入框: 类型/placeholder/maxlength/required/pattern/触发行为/防抖
Tab 筛选 列出所有 Tab, 切换后页码重置/滚动位置/幂等性
搜索类型 明确标注本地索引或云端搜索, 提供搜索配置
导航路由 按域名/前缀分组的完整路由表
API 端点 按功能域组织
登录状态机 含错误码分支 (如有)
会话管理 Cookie/localStorage/Token 交换机制
权限矩阵 未登录/已登录/VIP 差异表
错误/空态 至少 4 种错误场景测试
图片密度 超 50 张标记"偏高", 超 100 张标记"严重"
响应式 关键断点 (768px/1280px) 行为
缺口清单 所有 ⚠️ Gap 汇总, 标注优先级
技术债 至少 5 项评级

模块深度分析模式 (§M) — 分模块逐分支穷举 (v3.2)

当用户指定某个模块(导航标签/功能区域)进行深度分析时,执行此 5 阶段流水线。

触发条件

用户说"分析 XX 模块" / "深入分析 XX" / 指定具体导航标签名称 / 全站 Phase 0 后选择某模块深入。

5 阶段流水线

  • M-Phase 0 — 模块发现: 从主导航提取模块列表,展示给用户选择
  • M-Phase 1 — 边界映射: 点击导航进入模块 → 枚举子路由/Tab/可交互元素/表单,产出边界 JSON
  • M-Phase 2 — 穷举分支测试: 输入框 12 种分支(空值/XSS/Emoji/边界值/粘贴…)、下拉 4 种、日期 6 种(跨月/非法范围/键盘输入)、按钮 5 种(双击/loading)、筛选 7 种(多选组合/0结果)、分页 7 种(末页/越界/URL同步)
  • M-Phase 3 — API 分支覆盖: 每个端点测试 200+数据/200+空列表/400参数错误/401未登录/403无权限/500+Timeout 六种响应
  • M-Phase 4 — 状态机枚举: default→loading→data_loaded→empty/error→modal_open→submitting→success
  • M-Phase 5 — 编译模块文档: 8 章 (概述→路由→分支矩阵→API→状态机→验证规则→错误态→缺口清单)

注意事项

独立运行不依赖全站分析;分支爆炸优先覆盖表单/搜索/筛选;每个分支测试后恢复基准状态;截图按 {element}_{branch}_before/after.png 命名。

> 📝 完整代码模板 (模块发现、边界映射、分支执行器、API 覆盖、状态枚举) 见 reference.md §模块深度分析。

如果用户未明确指定模块名,先执行全站 Phase 0 初始扫描,提取导航标签列表:

def discover_modules(url):
    &quot;&quot;&quot;从当前页面提取所有可分析的模块列表。&quot;&quot;&quot;
    goto_url(url)
    time.sleep(3)
    wait_for_load()

    modules = json.loads(js(&quot;&quot;&quot;
    (function(){
        var items = [];
        var seen = new Set();
        // 从主导航提取模块
        document.querySelectorAll(
            &#x27;nav a, [role=&quot;navigation&quot;] a, [class*=&quot;nav&quot;] a, &#x27; +
            &#x27;[class*=&quot;tab&quot;]:not([class*=&quot;table&quot;]), [role=&quot;tab&quot;]&#x27;
        ).forEach(function(el){
            var text = (el.innerText || el.textContent || &#x27;&#x27;).trim().replace(/\\s+/g,&#x27; &#x27;);
            if (!text || text.length &gt; 25 || seen.has(text)) return;
            seen.add(text);
            var href = el.getAttribute(&#x27;href&#x27;) || &#x27;&#x27;;
            items.push({name: text, href: href.slice(0,120)});
        });
        return JSON.stringify(items.slice(0, 20));
    })();
    &quot;&quot;&quot;))

    print(&quot;发现以下功能模块:&quot;)
    for i, m in enumerate(modules):
        print(f&quot;  [{i+1}] {m[&#x27;name&#x27;]}  ({m[&#x27;href&#x27;]})&quot;)

    return modules

将模块列表展示给用户,格式:

发现 14 个功能模块:

  核心业务:
    [1] 酒店      [2] 机票      [3] 火车票
    [4] 旅游      [5] 门票·活动  [6] 汽车·船票
    [7] 用车

  特色功能:
    [8] AI行程助手  [9] 攻略·景点  [10] 旅游地图
    [11] 全球购     [12] 礼品卡

  其他:
    [13] 携程金融   [14] 企业商旅

请选择要深度分析的模块 (输入编号或名称, 支持多选):

> 📝 模块深度分析的完整代码模板 (M-Phase 0-5 所有实现) 见 reference.md §模块深度分析。


源码增强插件 (+src v3.3)

当项目目录下有 src/ 或 package.json 时,可选启用 4 个源码插件,对现有 Phase 注入源码级增强。

设计原则: 可选注入、降级容错 (类名→testid→标签→坐标)、emoji 标注来源 (🌐📂⚠️📝)、嵌入而非膨胀、先评估再增强 (覆盖率<30%警告)。

四个插件

  • +src:router: grep 路由文件 → 提取路由树 (path/name/component/meta/children/guards) → 与浏览器爬虫交叉验证 → 差异标注
  • +src:api: grep API 文件 → 提取函数签名 + 接口定义 (仅展开一层) → 与浏览器调用交叉验证 → 四等级覆盖度报告 (已验证/已定义未触发/需特定状态/无法判断)
  • +src:component: CSS 类名 grep 反向映射 (三级降级) → 读取源文件 → 提取 Props/条件分支/事件 → 补充交互分支矩阵
  • +src:store: 定位 Pinia/Vuex/Redux/Zustand 文件 → 提取 State/Actions/持久化配置 → 浏览器 window.__STORE__ 交叉验证

注意事项

覆盖率诚实标注、不阻塞现有流程、多仓库需逐个分析、敏感字段不写入文档、TypeScript 类型仅展开一层。

> 📝 完整源码插件代码 (评估函数、四种插件详细流程、输出标注格式) 见 reference.md §源码增强插件。


常见问题

Q: 页面受登录态影响怎么办?

部分页面 (如 B 站首页 /) 会因登录态不同而行为不同。策略:
1. 分别测试已登录和未登录状态的路由行为
2. 在文档中标注:"当前测试态: 已登录/未登录"
3. 使用 page_auth_ui() 检测登录态
4. 对认证系统的 JS 源码进行静态分析提取错误码

Q: SPA 页面导航链接不完整?

SPA 使用客户端路由, 初始 DOM 可能未包含所有链接。解决方案:
1. 先滚动到底部触发懒加载
2. 使用 page_nav_all_links() (agent_helpers.py 内建) 逐一点击侧栏导航
3. 对每个子路由重新执行 Phase 0-2

Q: 页面有反爬机制?

  • CDP 连接: 使用真实 Chrome, 非 headless
  • 登录态: 继承用户 Chrome 配置文件中的 cookie
  • 频率限制: 在请求间增加 time.sleep(2-5)
  • 验证码: 如遇验证码, 停止并提示用户手动完成

Q: API 监控捕获不完整?

performance.getEntriesByType(&#x27;resource&#x27;) 可能不捕获同域 API 请求。替代方案:

js(&quot;&quot;&quot;
(function(){
    var origFetch = window.fetch;
    window.fetch = function(url, opts){
        console.log(&#x27;[API] fetch:&#x27;, url);
        return origFetch.apply(this, arguments);
    };
})();
&quot;&quot;&quot;)

Q: Agent 分析结果不一致怎么办?

不同的 Agent 可能对同一行为有不同的推断。策略:
1. 保留矛盾证据, 标记为 P0 冲突缺口
2. 将冲突作为"行为缺口"记录, 安排实机测试解决
3. 取交集: 所有 Agent 都确认的行为作为确定事实, 有分歧的作为 Gap

Q: 全站分析和模块深度分析如何选择?

  • 全站模式: 接手新项目、竞品全貌了解、快速浏览。广度优先,14 章
  • 模块模式: 深入某个功能、编写测试用例基线、分支覆盖。深度优先,8 章但每章更密集
  • 建议: 先用全站模式获得全景图(1-2 小时),再对核心业务模块逐一深度分析(每个模块 1-3 小时)

Q: 模块深度分析的"分支爆炸"如何控制?

模块内可能有 50+ 可交互元素,每个元素 5-12 个分支,总分支数可能上千。
控制策略:
1. 优先级排序: 表单字段 > 搜索/筛选 > 按钮 > 链接。纯展示类链接降级为仅记录
2. 采样策略: 同类元素(如酒店列表中的 20 个酒店卡片链接)取前 3 个深度测试,其余记录为 Gap
3. 用户指定: 让用户指定最关心的 3-5 个子功能,其余标记为 P2 Gap
4. 时间控制: 单个模块深度分析不超过 3 小时


输出产物

产物 路径示例 说明
主规格文档 page-spec-{hostname}.md 完整 14+ 章 Markdown
截图目录 screenshots-{hostname}/ PNG 截图, 文档内联引用
API 响应数据 {site}_data/api_full_responses.json API 完整请求/响应 (v3.1)
API 结构数据 {site}_data/api_response_structures.json 浏览器内 fetch 获取的响应结构
API 时序数据 {site}_data/api_timing.json API 调用时序 (Performance API)
链接数据 {site}_data/links.json 全量链接与分类
交互元素数据 {site}_data/elements.json 交互元素详情
端点数据 {site}_data/endpoints.json API 端点 + 网络请求
Agent 报告 {site}_agent_{name}.md 各 Agent 的完整分析报告 (调试用)
OpenAPI Schema page-spec-{hostname}-openapi.json OpenAPI 3.0 规范 (v3.1+)
导航流图 内嵌于规格文档 Mermaid 页面流转图 (v3.1+)
模块规格文档 module-spec-{module_name}.md 单模块 8 章深度规格 (v3.2)
模块边界数据 {site}_data/{module}_boundary.json 模块内全量可交互元素清单
分支测试日志 {site}_data/{module}_branch_log.json 每个元素×每个分支的测试记录
模块截图 screenshots-{module}/ 按元素+分支命名的详细截图
源码评估报告 {site}_data/source-assessment.json 源码覆盖率、框架识别、置信度评分 (v3.3)
路由对比报告 {site}_data/router-diff.json 源码路由树 vs 浏览器爬虫结果 (v3.3)
API 覆盖度报告 {site}_data/api-coverage.json 四等级覆盖度 (已验证/已定义未触发/需特定状态/无法判断) (v3.3)
组件映射表 {site}_data/component-map.json CSS 类名 → 组件源文件映射 (v3.3)
Store 结构数据 {site}_data/store-snapshot.json 源码 Store 定义 + 浏览器运行时快照 (v3.3)

示例输出 (v3.x 实际数据)

网站 类型 文档大小 Agent 数 缺口数
skillhub.cn 市场 ~18KB 1 18
cn.vuejs.org 文档 ~20KB 1 5
www.csdn.net 社区 ~28KB 2 12
deepseek-transactions SaaS ~11KB — —
element.eleme.cn 文档 ~23KB — —
juejin.cn 社区 ~22KB — —
www.bilibili.com 社区 ~45KB — —
www.ctrip.com (全站) OTA 市场 ~32KB — 21
www.ctrip.com (酒店模块) OTA 模块 ~25KB — 35+

实际使用经验总结

挑战 解决方法
文档站无动态 API 静态站点适合侧重导航和搜索分析
图片过多导致性能问题 在文档中标记图片密度等级, 提出优化建议
登录模态框包含密码字段 识别但不填充, 在文档中标注认证流程和错误码
404 页面仍渲染完整导航 标题检查比 body 文本检查更可靠; 需同时检查友好消息
外部链接远多于内部链接 分离归类为广告/追踪/合作/社交
响应式 JS 模拟不触发重排 标注测试局限性, 建议 CDP 方式
编译文档时模板与真实数据不符 在提示词中明确禁止使用模板, 仅使用收集的数据
搜索类型误判 默认假设后验证: 检查 Algolia 配置 (window.docsearch, localStorage 中的 DOCSEARCH 键)
404 友好消息漏检 404 页面可能同时有标题"404"和情感化消息, 不能仅靠 title 判断
文档冲突管理 旧版本断言 vs 新证据矛盾时, 保留双方证据并标记 P0 Gap
Agent 输出合并 多 Agent 分析的取交集原则: 共同确认的写为事实, 有分歧的写为 Gap
http_get() 不带 Cookie API 返回空响应 — 改用浏览器内 fetch() 自动携带 Cookie
js() 大返回值为 None 分步采集: 先提取 URL 列表 (小), 再逐个 fetch 响应体 (每个几 KB)
POST 端点无文档 空 body 试 → 从 ValidationError 提取必填参数和枚举值 → 修正后重试
API 响应截断 responseBody.slice(0, 3000) 限制, 长列表数据需分页参数获取
截图未嵌入文档 截图后立即在对应章节用 ![描述](相对路径) 嵌入
截图超时导致流程中断 截图包裹 try/except,失败降级为文本断言 (js(&quot;document.body.innerText&quot;)) 继续执行,不抛异常
React/Vue 输入框赋值后状态未更新 用原生 HTMLInputElement.prototype.value setter + dispatchEvent(new Event(&#x27;input&#x27;)) + dispatchEvent(new Event(&#x27;change&#x27;)),勿直接 .value =
SPA 页面操作后内容未渲染 wait_for_load() 后追加 time.sleep(5+) + wait_for_network_idle(idle_ms=1000) + 滚动触达目标区域触发懒加载
generate_page_spec() 在 SPA 上超时 CDP mouseWheel 是 Chromium 已知 Bug (crbug.com/444929150)。超时时降级为 js(&quot;window.scrollBy(0,300)&quot;) + 手动 page_interactive_elements() 等采集函数
截图前目录不存在 → FileNotFoundError 每次截图前先 pathlib.Path(path).parent.mkdir(parents=True, exist_ok=True)
Windows 中文报告/数据文件乱码 所有文件写入用 open(path, &quot;w&quot;, encoding=&quot;utf-8&quot;),禁止依赖系统默认 GBK 编码
js() 无法引用 Python 变量 js() 代码在 Chrome 页面上下文执行,看不见 Python 变量。需传参时用 f-string 拼接: js(f&quot;el.value = {json.dumps(val)}&quot;)
CDP 调用失败无自动重试 CDP 层没有重试机制。任何 capture_screenshot()/js()/click_at_xy() 失败时原文报告给用户,不要自动重试超过 2 次 — 多次失败意味着环境问题而非临时抖动
分析完成后 daemon 未关闭 8 阶段跑完后 daemon 仍在后台持有 CDP 连接。建议任务结束时执行 browser-harness --reload 释放资源(下次需要时自动重启)
标签页意外切换导致命令失效 用户手动切标签/页面刷新/跳转 chrome-error:// 后 CDP session 失效 → 调用 ensure_real_tab() 自动恢复到用户最后一个真实页面

本 Skill 基于 Browser Harness 页面探索代理流程总结。版本: 3.3 — 源码增强插件(4 个可选 +src 插件: router/api/component/store)、模块深度分析模式(分模块逐分支穷举)、API 深度分析引擎(请求体/响应体完整捕获)、穷举交互引擎(每个元素逐一点击/输入/切换)、导航流图(Mermaid)、组件状态矩阵、无障碍深度报告(WCAG)、OpenAPI 3.0 schema 生成、P0/P1/P2 优化路线图。

常见问题

5 问
答案由本站依据条目字段整理
页面说明生成器怎么安装?

在支持 Skills 的客户端里执行:skillhub install user_0c6c8065/page-spec-generator。安装方式为未标注。装完刷新技能列表或重开客户端。

页面说明生成器支持哪些客户端?

资料没有标注宿主客户端,但只要客户端支持 Skills(Claude、Codex、Cursor 等),一般都能加载。

页面说明生成器权限高吗,安全吗?

权限级别为未标注权限。安装前先看它会读取或写入哪些内容。

页面说明生成器收费吗?

本站不代收费用,也没有标注具体价格。是否收费取决于技能本身和所用的模型或客户端,正式使用前按作者说明确认。

页面说明生成器用什么许可证?

许可证标注为 未说明(许可证不明确)。商用或二次分发前请到仓库确认条款原文。

热门专题

按场景挑技能
全部专题 →

技能内容以作者仓库为准;分类、权限级别与许可证状态的中文说明为中文整理,最近核验 未标注。