Axure Spec Scraper
使用 Playwright MCP 工具,從 Axure 分享連結中擷取設計稿 spec 內容,整理為可讀的 Markdown 文件。
工具說明: 本 skill 統一使用
mcp_playwright_browser_run_code_unsafe(參數名code)執行所有瀏覽器端操作。請勿使用mcp_playwright_browser_evaluate(此工具不存在或 schema 不同)。code的入口格式固定為async (page) => { ... }。
⚠️ 關鍵技術提醒
- 頁面環境 vs Node.js 環境:所有對
window、document的訪問必須在page.evaluate()或page.waitForFunction()的回調函數內進行。- ❌ 錯誤:
const doc = window.$axure.document;(直接在 Node.js 執行 → window 不存在) - ✅ 正確:
await page.evaluate(() => { const doc = window.$axure.document; return doc; })
- ❌ 錯誤:
- 務必確保每一段訪問瀏覽器對象的代碼都被
page.evaluate()或page.waitForFunction()的箭頭函數包裹。
執行前檢查清單
在執行每個步驟的代碼前,必須確認:
- 代碼入口是
async (page) => { ... }格式 - 所有
window.*訪問都在page.evaluate(() => { ... })內 - 所有
document.*訪問都在page.evaluate(() => { ... })內 -
page.waitForFunction()的條件函數使用() => { ... }箭頭函數 - 頁面導航後,重新等待 Axure JS 水合(
page.waitForFunction(() => window.$axure))
步驟一:確認 Playwright MCP 可用
使用 tool_search 查詢關鍵字 playwright browser navigate snapshot。
執行檢查清單
✓ 找到 mcp_playwright_browser_navigate 工具
✓ 找到 mcp_playwright_browser_run_code_unsafe 工具
✓ 找到 mcp_playwright_browser_snapshot 工具
若以上工具都找到 → 繼續執行。
若找不到 → 通知使用者:
Playwright MCP 目前未連線。請在 VS Code 中執行:
Cmd+Shift+P→ 搜尋 MCP: List Servers- 確認
playwright狀態為 Connected - 若未連線,請確認
.vscode/mcp.json已設定 playwright server 並重新啟動 VS Code
停止作業,等待使用者確認後再繼續。
步驟二:取得 Axure 網址
若使用者未提供網址,詢問:
請提供 Axure 設計稿的分享網址(格式通常為
https://xxxx.axshare.com/?id=xxxxxx)
步驟三:導航並取得頁面結構
執行檢查清單
✓ 已呼叫 mcp_playwright_browser_navigate 導航至 Axure 連結
✓ 回應顯示 Page Title(頁面已載入)
✓ 無密碼驗證框提示
步驟:
- 呼叫
mcp_playwright_browser_navigate導航至目標網址(https://{share-id}.axshare.com/?id={page-id}) - 確認頁面載入(回應中有 Page Title)
- 偵測 access code 驗證:若 snapshot 或頁面標題出現密碼/驗證輸入框,停止並請使用者直接在瀏覽器輸入密碼,確認後再繼續。
- 使用
mcp_playwright_browser_run_code_unsafe等待$axure注入並取得頁面結構:
// 【頁面環境】此代碼在頁面上下文中執行,可訪問 window、document
async (page) => {
// ✓ 在頁面環境中等待 $axure 注入
await page.waitForFunction(() => window.$axure && window.$axure.document, { timeout: 10000 });
// ✓ 在頁面環境中訪問並返回 $axure 數據
return await page.evaluate(() => {
const doc = window.$axure.document; // ✓ window 存在
return JSON.stringify(doc.pages || doc.sitemap, null, 2);
});
}
此步驟可取得所有頁面的 pageName、id、url、資料夾結構(rootNodes)。
步驟四:擷取指定頁面 spec 內容
執行檢查清單
✓ 頁面已完全載入(能訪問 $axure)
✓ 使用者未指定頁面時,使用當前頁
只抓使用者指定的頁面(預設為當前頁),不需遍歷所有頁面。
使用 mcp_playwright_browser_run_code_unsafe 從 spec frame 抓取文字。方法一最常用;若回傳空字串,改用方法二。
方法一:主頁面或 iframe(常規場景)
// 【頁面環境】此代碼在頁面上下文中執行
async (page) => {
// ✓ page.evaluate() 保證在頁面環境中執行
return await page.evaluate(() => {
const result = [];
// 嘗試直接從主頁面的 iframe 內取得(同 origin 場景)
const iframe = document.querySelector('iframe');
let body = null;
try {
if (iframe && iframe.contentDocument) {
body = iframe.contentDocument.body;
}
} catch (e) {
// cross-origin iframe,先跳過
}
// 若 iframe 不可用,嘗試取主頁面 body(部分 Axure 版本 spec 直接在主頁)
if (!body) body = document.body;
body.querySelectorAll('p, h1, h2, h3, h4, h5, h6, li, td, th').forEach(el => {
const directText = Array.from(el.childNodes)
.filter(n => n.nodeType === Node.TEXT_NODE)
.map(n => n.textContent.trim())
.join('');
const text = directText || el.innerText.trim();
if (text) result.push(text);
});
// 去除重複行並過濾空白
return [...new Set(result)].filter(Boolean).join('\n---\n');
});
}
方法二:透過 Playwright frame API(當方法一回傳空字串時)
若方法一回傳空字串或錯誤,改用 mcp_playwright_browser_run_code_unsafe:
// 【混合環境】頁面層級訪問 frames(),frame 層級訪問 DOM
async (page) => {
// ✓ 這裡在 Node.js 環境,page 是 Playwright Page 對象
const frames = page.frames(); // ✓ page.frames() 是 Node.js API
const specFrame = frames.find(f =>
f.url().includes('axshare.com') && f !== page.mainFrame()
);
if (!specFrame) return 'no spec frame found';
// ✓ 切換到 frame 的頁面環境
return await specFrame.evaluate(() => { // ✓ frame.evaluate() 在 frame 的頁面環境執行
const result = [];
document.body.querySelectorAll('p, h1, h2, h3, h4, h5, h6, li, td, th').forEach(el => {
const text = el.innerText.trim();
if (text) result.push(text);
});
return [...new Set(result)].filter(Boolean).join('\n---\n');
});
}
若需要切換頁面,使用 mcp_playwright_browser_navigate:
- URL 格式:
https://{share-id}.axshare.com/#id={page-id}&p={encoded-page-name} - 切換後重新執行步驟三(等待
$axure水合)再執行本步驟。
步驟五:轉換為 Markdown
根據擷取內容,依以下結構輸出:
# {頁面標題} 畫面說明
> **來源:** {原始網址}
> **路徑:** {breadcrumb 路徑}
> **頁面 ID:** `{id}`
> **擷取日期:** {YYYY-MM-DD}
---
## 重要異動
{異動摘要}
---
## 改版項目總覽
| 項目標號 | 區塊 | 說明摘要 |
|:---:|---|---|
| 1 | {區塊名} | {說明} |
---
## {標號}. {區塊名稱}
{詳細說明,使用條列與子清單}
### {子標題(如有排序規則、補充說明等)}
{內容}
格式原則:
- 標號對應的區塊各自為一個
##段落 - 條列項目保持
-格式 - 有序清單(險種列表等)使用
1.格式 - 表格用於排序規則、欄位對照等結構性資料
- 重要詞彙用
**粗體**標示
步驟六:輸出檔案
若使用者要求存檔(如「輸出 pm_spec.md」),使用 create_file 建立檔案於 workspace 根目錄。
檔案命名慣例:pm_spec.md(或使用者指定名稱)
輸出完成後,告知使用者:
✅
pm_spec.md已產出至根目錄。
下一步:執行 figma-spec-extractor 擷取視覺規格,產出design_spec.md。
待 design_spec 完成後,可執行 frontend-spec-synthesizer 讀取pm_spec.md+design_spec.md,產出frontend_sdd.md(三份文件皆留在專案根目錄)。
常見實作錯誤
❌ 錯誤 #1:在 Node.js 環境訪問 window
// ❌ 錯誤 — window is not defined(在 Node.js 執行)
async (page) => {
await page.waitForFunction(() => window.$axure && window.$axure.document, { timeout: 10000 });
const doc = window.$axure.document; // ❌ 在這裡 window 不存在!
return JSON.stringify(doc.pages);
}
修正: 將訪問 window 的代碼放在 page.evaluate() 的回調中
// ✅ 正確 — window 訪問在頁面環境
async (page) => {
await page.waitForFunction(() => window.$axure && window.$axure.document, { timeout: 10000 });
return await page.evaluate(() => { // ✅ 進入頁面環境
const doc = window.$axure.document; // ✓ window 現在存在
return JSON.stringify(doc.pages);
});
}
❌ 錯誤 #2:混淆 page 和 frame 的環境
// ❌ 錯誤 — page.frames() 後試圖直接訪問 frame 內容
const frames = page.frames(); // Node.js 環境
const body = frames[1].document.body; // ❌ frames[1].document 不可用
修正: 用 frame.evaluate() 進入 frame 的頁面環境
// ✅ 正確
const frames = page.frames();
const content = await frames[1].evaluate(() => {
return document.body.innerText; // ✓ frame 的頁面環境
});
注意事項與除錯指引
| 現象 | 原因 | 處理方式 |
|---|---|---|
window is not defined |
訪問 window 的代碼不在 page.evaluate() 或 page.waitForFunction() 的回調中 |
務必將所有 window/document 訪問包在 await page.evaluate(() => { ... }) 中 |
$axure is not defined |
JS 尚未水合完畢 | 確保 waitForFunction(() => window.$axure && window.$axure.document) 在 evaluate 之前執行 |
no iframe / 空字串 |
cross-origin iframe 或 spec 在主頁面 | 改用方法二(Playwright page.frames() API,見步驟四) |
| 頁面出現密碼輸入框 | Axure access code 保護 | 請使用者直接在瀏覽器輸入密碼後再繼續 |
| 內容重複 | Axure DOM 有巢狀文字節點 | 已在擷取邏輯加入 Set 去重 |
回傳 SecurityError |
iframe 跨 origin | 切換為步驟四方法二(specFrame.evaluate()) |
window.$axure.document.pages.rootNodes包含完整頁面樹狀結構(含資料夾)- 不需要截圖(
mcp_playwright_browser_take_screenshot),文字擷取已足夠 - 絕對不要使用
mcp_playwright_browser_evaluate,此工具不存在或 schema 不同,會導致驗證錯誤