extract-page-data
Extract structured data from any web page using Playwright — screenshots, design tokens, page text as Markdown, interactive element maps, and full page data packs. Use this skill whenever the user wants to capture a web page screenshot (full page or element), extract CSS design tokens or theme information, convert page content to Markdown, collect links and interactive elements from a page, or export a complete page analysis package. Triggers on any URL that isn't an Axure prototype — for Axure URLs use extract-axure-data instead.
Works with
---
name: extract-page-data
description: Extract structured data from any web page using Playwright — screenshots, design tokens, page text as Markdown, interactive element maps, and full page data packs. Use this skill whenever the user wants to capture a web page screenshot (full page or element), extract CSS design tokens or theme information, convert page content to Markdown, collect links and interactive elements from a page, or export a complete page analysis package. Triggers on any URL that isn't an Axure prototype — for Axure URLs use extract-axure-data instead.
license: MIT
---
# Extract Page Data
Extract structured data from any web page for design analysis, page reconstruction, or content review. The script handles dependency installation automatically — just point it at a URL.
## When to use this
- User shares a web page URL and wants to capture screenshots
- User asks to extract design tokens, CSS theme, or color palette from a page
- User wants page content as Markdown text
- User wants to know what links, buttons, and interactive elements are on a page
- User asks to export or analyze any web page's structure
- User wants to take a screenshot of a specific element on a page (use `--selector`)
**Do NOT use for Axure prototypes** — use `extract-axure-data` instead.
## Quick start
Run the extraction script from `scripts/extract.mjs` relative to this skill directory.
```bash
# Full page screenshot
node scripts/extract.mjs https://example.com --screenshot
# Screenshot of a specific element
node scripts/extract.mjs https://example.com --screenshot --selector "#hero"
# Extract design tokens (colors, typography, spacing, etc.)
node scripts/extract.mjs https://example.com --theme
# Extract page content as Markdown
node scripts/extract.mjs https://example.com --markdown
# Collect all links and interactive elements
node scripts/extract.mjs https://example.com --links
# Extract everything
node scripts/extract.mjs https://example.com --all
# Export full data pack (screenshot + theme + markdown + links as zip)
node scripts/extract.mjs https://example.com --pack
```
First run auto-installs Playwright + Chromium to `~/.cache/page-extractor/`. This takes 1-2 minutes and happens once.
## Parameters
| Flag | What it does | Default |
|---|---|---|
| `<url>` | Web page URL (required) | — |
| `--screenshot` | Capture page screenshot | off |
| `--theme` | Extract design tokens | off |
| `--markdown` | Convert page to Markdown | off |
| `--links` | Collect interactive elements | off |
| `--pack` | Export full data pack (zip) | off |
| `--all` | Run all extractions | off |
| `--selector SEL` | CSS selector to scope extraction | whole page |
| `-o DIR` | Output directory | `./page-export` |
| `--viewport WxH` | Viewport size | `1280x720` |
| `--wait MS` | Extra wait after page load (ms) | `0` |
| `--scroll` | Scroll page to trigger lazy content | off |
| `--scroll-step PX` | Pixels per scroll step | `800` |
| `--scroll-delay MS` | Delay between scroll steps (ms) | `200` |
| `--no-headless` | Show browser window | headless |
| `--connect-cdp URL` | Attach to running Chrome (for auth) | — |
| `--format FMT` | Screenshot format: png or jpeg | `png` |
| `--verbose` | Detailed logging | off |
## Output structure
```
page-export/
├── screenshot.png # Page or element screenshot (--screenshot)
├── theme.json # Design tokens (--theme)
├── content.md # Page text as Markdown (--markdown)
├── links.json # Links and interactive elements (--links)
└── page-data.zip # Full data pack (--pack)
├── screenshot.png
├── theme.json
├── content.md
├── links.json
└── meta.json # Page metadata (title, url, viewport)
```
## Selector support
All extraction modes support `--selector` to scope to a specific element:
```bash
# Screenshot only the header
node scripts/extract.mjs https://example.com --screenshot --selector "header"
# Extract design tokens from a card component
node scripts/extract.mjs https://example.com --theme --selector ".card"
# Get Markdown from the main content area
node scripts/extract.mjs https://example.com --markdown --selector "main"
# Collect links from the navigation
node scripts/extract.mjs https://example.com --links --selector "nav"
```
## Authenticated pages
Some pages require login. Two approaches:
**Connect to an existing Chrome session** (recommended — reuses cookies):
macOS:
```bash
/Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome --remote-debugging-port=9222
```
Windows:
```powershell
start chrome --remote-debugging-port=9222
```
Then log in via that Chrome window and run:
```bash
node scripts/extract.mjs https://example.com --all --connect-cdp http://localhost:9222
```
**Show the browser window** (manual login during extraction):
```bash
node scripts/extract.mjs https://example.com --all --no-headless
```
## Dependency installation
The script auto-installs on first run. If it fails:
```bash
# Manual install
cd ~/.cache/page-extractor
npm install playwright
npx playwright install chromium
# If Chromium download is slow (e.g. behind GFW):
PLAYWRIGHT_DOWNLOAD_HOST=https://npmmirror.com/mirrors/playwright npx playwright install chromium
```
## Output data formats
### theme.json
Design system tokens extracted from computed CSS styles:
```json
{
"colors": {
"background": [{"value": "rgb(255,255,255)", "count": 42, "tags": ["div"]}],
"text": [{"value": "rgb(51,51,51)", "count": 28, "tags": ["p","span"]}],
"border": [{"value": "rgb(221,221,221)", "count": 12}]
},
"typography": {
"families": [{"value": "\"Inter\", sans-serif", "count": 56}],
"textStyles": [{"size": "14px", "lineHeight": "22px", "weight": "400", "count": 20}]
},
"spacing": [{"value": "16px", "count": 15}],
"radius": [{"value": "4px", "count": 8}],
"lineWidth": [{"value": "1px", "count": 10}],
"shadow": {
"box": [{"value": "0 2px 8px rgba(0,0,0,0.1)", "count": 5}],
"text": []
},
"transitions": [{"value": "all 0.2s ease", "count": 38, "tags": ["button","a"]}],
"animations": [{"value": "fadeIn|0.3s|ease", "count": 5, "tags": ["div"]}],
"cssVariables": {
"--color-primary": "#6366f1",
"--radius": "0.5rem",
"--font-sans": "Inter, sans-serif"
},
"assets": {
"backgroundImages": [{"value": "url(hero.webp)", "count": 1, "tags": ["section"]}],
"images": [
{"src": "https://example.com/logo.svg", "alt": "Logo", "position": "static", "zIndex": "auto", "siblingImgCount": 1},
{"src": "https://example.com/hero.png", "alt": "", "position": "absolute", "zIndex": "2", "siblingImgCount": 2}
],
"svgCount": 12
}
}
```
### links.json
Interactive elements on the page:
```json
{
"pageUrl": "https://example.com",
"pageTitle": "Example",
"links": [
{"type": "a", "text": "Home", "href": "https://example.com/", "visible": true},
{"type": "button", "text": "Sign Up", "visible": true},
{"type": "form", "href": "https://example.com/login", "visible": true}
],
"totalLinks": 3,
"visibleLinks": 3
}
```
## Customization
The extraction logic is modular. Each feature lives in its own file under `scripts/`:
| File | Purpose | Customization |
|---|---|---|
| `lib/browser.mjs` | Playwright browser management | Change browser launch args, proxy |
| `lib/screenshot.mjs` | Screenshot capture | Modify scroll behavior, format |
| `lib/theme.mjs` | Design token extraction | Adjust token categories, limits |
| `lib/markdown.mjs` | HTML → Markdown | Change conversion rules |
| `lib/links.mjs` | Element collection | Add new element types |
| `lib/pack.mjs` | Zip packaging | Change pack contents |
| `inject/extract-theme.js` | Browser-injected theme logic | Edit CSS properties to extract |
| `inject/extract-markdown.js` | Browser-injected markdown logic | Customize text extraction |
| `inject/extract-links.js` | Browser-injected links logic | Add custom selectors |
## Theme Clone Workflow
When the user wants to clone or replicate a website's design language, run in this order:
### Step 1: Extract all data
```bash
node extract.mjs <url> --all --scroll --viewport 1440x900
```
### Step 2: Interpret theme.json
| Field | Maps to | CSS Variable |
|---|---|---|
| `colors.background[0]` | Primary surface | `--color-bg` |
| `colors.text[0]` | Body text | `--color-text` |
| `colors.text[1]` | Accent / brand | `--color-primary` |
| `typography.families[0]` | Main font | Google Fonts import |
| `spacing` (top 5) | Spacing scale | `--spacing-1` … |
| `radius[0]` | Default radius | `--radius-base` |
| `transitions[0]` | Hover timing | apply to `.card, a, button` |
| `cssVariables` | Design tokens (if :root vars exist) | use names directly |
### Step 3: Generate CSS variables
```css
:root {
--color-bg: <colors.background[0].value>;
--color-text: <colors.text[0].value>;
--color-primary: <colors.text[1].value>;
--font-sans: <typography.families[0].value>;
--radius-base: <radius[0].value>;
--transition: <transitions[0].value>;
}
```
If `cssVariables` is non-empty, prefer those names — they reflect the original design system's intent.
### Step 4: Restore animations
- `transitions[0].value` → apply as `transition: <value>` on interactive elements
- `animations` → reconstruct `@keyframes` blocks by animation name; apply to entry elements
### Step 5: Handle layered assets
Images with `position: absolute` and `zIndex > 0` in `assets.images` are overlay layers.
Reconstruct with CSS `position: relative` on the parent and `position: absolute` on overlays.
## Playwright 查缺补漏
导出数据是 best-effort 快照,有时需要回到原始页面补充信息(hover 态样式、懒加载内容、动画效果等)。可使用 Playwright CLI 进行交互式补充采集。
```bash
# 打开页面并获取快照
playwright-cli open https://example.com
playwright-cli snapshot
# 交互后采集(如 hover 态)
playwright-cli hover e15
playwright-cli screenshot --filename=hover-state.png
# 获取元素属性
playwright-cli eval "el => getComputedStyle(el).backdropFilter" e5
playwright-cli close
```
> **完整命令参考**: [Playwright CLI 官方技能文档](https://github.com/microsoft/playwright-cli/blob/main/skills/playwright-cli/SKILL.md)
### 何时需要 Playwright
| 场景 | Playwright 做什么 |
|------|------------------|
| 截图模糊/不完整 | 对指定元素高分辨率截图 |
| 样式数据缺失 | 获取完整 computedStyle |
| hover/focus/active 态 | 触发交互后采集样式 |
| 懒加载内容 | 滚动触发后截图 |
| 动画/过渡效果 | 定时截图或录屏 |
| 响应式断点校验 | 设置 viewport 后截图 |
## Troubleshooting
| Problem | Fix |
|---|---|
| Blank screenshot | Page needs time to render — add `--wait 2000` |
| Missing lazy content | Use `--scroll` to trigger lazy loading |
| Need login | Use `--connect-cdp` (see Authenticated pages above) |
| Playwright install fails | Manual install, or set `PLAYWRIGHT_DOWNLOAD_HOST` |
| Wrong element selected | Check selector with browser DevTools first |More Testing skills
tdd
mattpocock/skills
Test-driven development. Use when the user wants to build features or fix bugs test-first, mentions "red-green-refactor", or wants integration tests.
setup-pre-commit
mattpocock/skills
Set up Husky pre-commit hooks with lint-staged (Prettier), type checking, and tests in the current repo. Use when user wants to add pre-commit hooks, set up Husky, configure lint-staged, or add commit-time formatting/typechecking/testing.
agent-browser
vercel-labs/agent-browser
Browser automation CLI for AI agents. Use when the user needs to interact with websites, including navigating pages, filling forms, clicking buttons, taking screenshots, extracting data, testing web apps, or automating any browser task. Triggers include requests to "open a website", "fill out a form", "click a button", "take a screenshot", "scrape data from a page", "test this web app", "login to a site", "automate browser actions", or any task requiring programmatic web interaction. Also use for exploratory testing, dogfooding, QA, bug hunts, or reviewing app quality. Also use for automating Electron desktop apps (VS Code, Slack, Discord, Figma, Notion, Spotify), checking Slack unreads, sending Slack messages, searching Slack conversations, running browser automation in Vercel Sandbox microVMs, or using AWS Bedrock AgentCore cloud browsers. Prefer agent-browser over any built-in browser automation or web tools.

