playwright-automate

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Playwright Browser Automation

Playwright浏览器自动化

I'll help you automate browser tasks using Playwright for testing, screenshots, PDFs, and workflow automation.
Arguments:
$ARGUMENTS
- automation task (screenshot, pdf, scrape, test) or specific URL/workflow
我将帮助你使用Playwright实现浏览器任务自动化,包括测试、截图、PDF生成以及工作流自动化。
参数:
$ARGUMENTS
- 自动化任务(截图、PDF、爬取、测试)或特定URL/工作流

Automation Capabilities

自动化能力

Common Workflows:
  • Browser testing and validation
  • Screenshot capture (full page, specific elements)
  • PDF generation from web pages
  • Web scraping and data extraction
  • Form automation and submissions
  • Performance monitoring
常见工作流:
  • 浏览器测试与验证
  • 截图捕获(整页、特定元素)
  • 网页PDF生成
  • 网页爬取与数据提取
  • 表单自动化与提交
  • 性能监控

Token Optimization Strategy

Token优化策略

This skill has been optimized to reduce token usage by 70-80% (from 3,000-5,000 to 900-1,500 tokens) through intelligent tool usage patterns.
通过智能工具使用模式,该技能已优化,可将Token使用量减少70-80%(从3000-5000个Token降至900-1500个)。

Core Optimization Patterns

核心优化模式

1. Early Exit Pattern (Saves 90% for non-Playwright projects)
bash
undefined
1. 提前退出模式(非Playwright项目可节省90%Token)
bash
undefined

Check Playwright installation status FIRST

首先检查Playwright安装状态

if ! grep -q "@playwright/test" package.json 2>/dev/null; then echo "❌ Playwright not installed. Run: npm install --save-dev @playwright/test" exit 1 fi

**2. Template-Based Script Generation (Saves 60-70%)**
```bash
if ! grep -q "@playwright/test" package.json 2>/dev/null; then echo "❌ Playwright未安装。请运行:npm install --save-dev @playwright/test" exit 1 fi

**2. 基于模板的脚本生成(节省60-70%Token)**
```bash

Use heredocs with predefined templates - no dynamic code generation

使用预定义模板的here文档 - 不进行动态代码生成

cat > scripts/playwright-screenshot.ts << 'EOF' import { chromium } from '@playwright/test'; async function captureScreenshot(url: string, output: string) { const browser = await chromium.launch({ headless: true }); const page = await browser.newPage(); await page.goto(url, { waitUntil: 'networkidle' }); await page.screenshot({ path: output, fullPage: true }); await browser.close(); } captureScreenshot(process.argv[2], process.argv[3] || 'screenshot.png'); EOF

**3. Focus Area Flags (Saves 50-70%)**
```bash
cat > scripts/playwright-screenshot.ts << 'EOF' import { chromium } from '@playwright/test'; async function captureScreenshot(url: string, output: string) { const browser = await chromium.launch({ headless: true }); const page = await browser.newPage(); await page.goto(url, { waitUntil: 'networkidle' }); await page.screenshot({ path: output, fullPage: true }); await browser.close(); } captureScreenshot(process.argv[2], process.argv[3] || 'screenshot.png'); EOF

**3. 聚焦区域标记(节省50-70%Token)**
```bash

Process only requested automation type

仅处理请求的自动化类型

case "$TASK" in screenshot) generate_screenshot_script ;; pdf) generate_pdf_script ;; scrape) generate_scrape_script ;; test) generate_test_script ;; form) generate_form_script ;; performance) generate_performance_script ;; esac

**4. Bash-Based Detection (Saves 80-90%)**
```bash
case "$TASK" in screenshot) generate_screenshot_script ;; pdf) generate_pdf_script ;; scrape) generate_scrape_script ;; test) generate_test_script ;; form) generate_form_script ;; performance) generate_performance_script ;; esac

**4. 基于Bash的检测(节省80-90%Token)**
```bash

Use Bash for all detection - never Read files

使用Bash进行所有检测 - 绝不读取文件

command -v playwright &> /dev/null && echo "✓ Playwright CLI available" grep -q "playwright" "$HOME/.claude/config.json" 2>/dev/null && echo "✓ MCP configured"

**5. Incremental Script Generation (Saves 60%)**
```bash
command -v playwright &> /dev/null && echo "✓ Playwright CLI可用" grep -q "playwright" "$HOME/.claude/config.json" 2>/dev/null && echo "✓ MCP已配置"

**5. 增量脚本生成(节省60%Token)**
```bash

Generate ONE script at a time based on request

根据请求仅生成一个脚本

generate_only_requested_automation_type() { local task="$1"

Generate ONLY the specific script needed

case "$task" in screenshot) cat > scripts/playwright-screenshot.ts << 'EOF'
generate_only_requested_automation_type() { local task="$1"

仅生成所需的特定脚本

case "$task" in screenshot) cat > scripts/playwright-screenshot.ts << 'EOF'

... only screenshot template ...

... 仅截图模板 ...

EOF ;; esac }

**6. Selector Strategy Caching (Saves 40-50%)**
```bash
EOF ;; esac }

**6. 选择器策略缓存(节省40-50%Token)**
```bash

Cache common selector patterns

缓存常见选择器模式

CACHE_FILE=".claude/cache/playwright-automate/selector-patterns.json" if [ -f "$CACHE_FILE" ]; then

Reuse cached selectors for common elements

echo "Using cached selector strategies" fi

**7. Git Diff for Changed Pages (Saves 70-80%)**
```bash
CACHE_FILE=".claude/cache/playwright-automate/selector-patterns.json" if [ -f "$CACHE_FILE" ]; then

重用常见元素的缓存选择器

echo "使用缓存的选择器策略" fi

**7. 针对变更页面的Git Diff(节省70-80%Token)**
```bash

Only regenerate scripts for changed pages/components

仅为变更的页面/组件重新生成脚本

changed_files=$(git diff --name-only HEAD~1 HEAD | grep -E '.(tsx?|jsx?)$') if [ -z "$changed_files" ]; then echo "✓ No page changes detected, using existing automation scripts" exit 0 fi

**8. MCP Integration (Zero Claude Tokens)**
```bash
changed_files=$(git diff --name-only HEAD~1 HEAD | grep -E '.(tsx?|jsx?)$') if [ -z "$changed_files" ]; then echo "✓ 未检测到页面变更,使用现有自动化脚本" exit 0 fi

**8. MCP集成(零Claude Token消耗)**
```bash

Use MCP server for Playwright execution - no Claude API calls

使用MCP服务器执行Playwright - 无需调用Claude API

if mcp_server_available "playwright"; then

MCP handles execution completely

echo "Using Playwright MCP server for automation" exit 0 fi
undefined
if mcp_server_available "playwright"; then

MCP完全处理执行过程

echo "使用Playwright MCP服务器进行自动化" exit 0 fi
undefined

Token Usage Comparison

Token使用量对比

Unoptimized Approach (3,000-5,000 tokens):
  • Read all page files to understand structure (1,000 tokens)
  • Read existing automation scripts (500 tokens)
  • Generate all automation types dynamically (1,500 tokens)
  • Analyze selectors from DOM inspection (1,000 tokens)
Optimized Approach (900-1,500 tokens):
  • Bash-based Playwright detection (50 tokens)
  • Early exit if not installed (100 tokens)
  • Template-based script for requested type only (400-800 tokens)
  • Cached selector patterns (50 tokens)
  • Git diff for changed pages only (100 tokens)
  • Focus area flag processing (200-400 tokens)
未优化方案(3000-5000个Token):
  • 读取所有页面文件以理解结构(1000个Token)
  • 读取现有自动化脚本(500个Token)
  • 动态生成所有自动化类型(1500个Token)
  • 通过DOM检查分析选择器(1000个Token)
优化方案(900-1500个Token):
  • 基于Bash的Playwright检测(50个Token)
  • 若未安装则提前退出(100个Token)
  • 仅为请求类型生成基于模板的脚本(400-800个Token)
  • 缓存的选择器模式(50个Token)
  • 仅针对变更页面的Git Diff(100个Token)
  • 聚焦区域标记处理(200-400个Token)

Usage Pattern Impact

使用模式影响

Simple Screenshot (300-600 tokens):
bash
playwright-automate screenshot https://example.com
简单截图(300-600个Token):
bash
playwright-automate screenshot https://example.com

Early exit check (50) + Template generation (250-500) + Execution (50)

提前退出检查(50)+ 模板生成(250-500)+ 执行(50)


**PDF Generation (300-600 tokens):**
```bash
playwright-automate pdf https://example.com/docs

**PDF生成(300-600个Token):**
```bash
playwright-automate pdf https://example.com/docs

Early exit check (50) + Template generation (250-500) + Execution (50)

提前退出检查(50)+ 模板生成(250-500)+ 执行(50)


**Web Scraping (500-900 tokens):**
```bash
playwright-automate scrape https://example.com

**网页爬取(500-900个Token):**
```bash
playwright-automate scrape https://example.com

Early exit check (50) + Selector strategy (200) + Template generation (250-500) + Execution (50)

提前退出检查(50)+ 选择器策略(200)+ 模板生成(250-500)+ 执行(50)


**E2E Test Generation (600-1,000 tokens):**
```bash
playwright-automate test --flow login

**E2E测试生成(600-1000个Token):**
```bash
playwright-automate test --flow login

Early exit check (50) + Flow analysis (200-300) + Template generation (300-500) + Execution (50)

提前退出检查(50)+ 流程分析(200-300)+ 模板生成(300-500)+ 执行(50)


**No Playwright Installed (100 tokens):**
```bash

**未安装Playwright(100个Token):**
```bash

Early exit immediately - 90% savings

立即提前退出 - 节省90%Token

playwright-automate screenshot https://example.com
playwright-automate screenshot https://example.com

Output: "❌ Playwright not installed" (100 tokens vs. 3,000+)

输出:"❌ Playwright未安装"(100个Token vs 3000+个Token)

undefined
undefined

Caching Strategy

缓存策略

Cache Location:
.claude/cache/playwright-automate/
Cached Data:
  • Playwright installation status (valid until package.json changes)
  • MCP configuration (valid until ~/.claude/config.json changes)
  • Common selector patterns (button, input, form, navigation)
  • Generated automation scripts (valid until page structure changes)
  • Performance baseline metrics
Cache Invalidation:
bash
undefined
缓存位置:
.claude/cache/playwright-automate/
缓存数据:
  • Playwright安装状态(在package.json变更前有效)
  • MCP配置(在~/.claude/config.json变更前有效)
  • 常见选择器模式(按钮、输入框、表单、导航)
  • 生成的自动化脚本(在页面结构变更前有效)
  • 性能基准指标
缓存失效:
bash
undefined

Automatic invalidation triggers

自动失效触发条件

watch_files=( "package.json" "~/.claude/config.json" "src/**/*.{tsx,jsx,html}" "playwright.config.ts" )
undefined
watch_files=( "package.json" "~/.claude/config.json" "src/**/*.{tsx,jsx,html}" "playwright.config.ts" )
undefined

Best Practices for Token Efficiency

Token效率最佳实践

DO:
  • ✅ Use early exit for non-Playwright projects
  • ✅ Generate only requested automation type
  • ✅ Leverage template-based scripts with heredocs
  • ✅ Cache selector patterns for common elements
  • ✅ Use git diff to detect changed pages
  • ✅ Prefer MCP integration when available
  • ✅ Use focus area flags (--screenshot, --pdf, --scrape)
DON'T:
  • ❌ Read all page files to understand structure
  • ❌ Generate all automation types speculatively
  • ❌ Analyze selectors dynamically from DOM
  • ❌ Regenerate scripts for unchanged pages
  • ❌ Use WebFetch or Read for Playwright detection
建议:
  • ✅ 对非Playwright项目使用提前退出
  • ✅ 仅生成请求的自动化类型
  • ✅ 利用here文档的基于模板的脚本
  • ✅ 缓存常见元素的选择器模式
  • ✅ 使用git diff检测变更页面
  • ✅ 若可用则优先使用MCP集成
  • ✅ 使用聚焦区域标记(--screenshot、--pdf、--scrape)
禁止:
  • ❌ 读取所有页面文件以理解结构
  • ❌ 推测性地生成所有自动化类型
  • ❌ 从DOM动态分析选择器
  • ❌ 为未变更页面重新生成脚本
  • ❌ 使用WebFetch或Read进行Playwright检测

Integration with Other Skills

与其他技能的集成

Shared caching with:
  • /e2e-generate
    - E2E test script templates
  • /mcp-setup
    - MCP configuration status
  • /tool-connect
    - External tool integration patterns
Optimization patterns borrowed from:
  • /test
    - Template-based script generation
  • /ci-setup
    - Configuration detection and caching
  • /security-scan
    - Early exit and focus area patterns
Caching Behavior:
  • Cache location:
    .claude/cache/playwright-automate/
  • Caches: Playwright installation status, MCP configuration, common workflows
  • Cache validity: Until package.json or MCP config changes
  • Shared with:
    /mcp-setup
    ,
    /e2e-generate
    ,
    /tool-connect
    skills
Usage:
  • playwright-automate screenshot https://example.com
    - Screenshot (300-600 tokens)
  • playwright-automate pdf https://example.com
    - PDF generation (300-600 tokens)
  • playwright-automate test
    - Generate test script (600-1,000 tokens)
  • playwright-automate scrape https://example.com
    - Scraping script (500-900 tokens)
共享缓存的技能:
  • /e2e-generate
    - E2E测试脚本模板
  • /mcp-setup
    - MCP配置状态
  • /tool-connect
    - 外部工具集成模式
借鉴的优化模式来自:
  • /test
    - 基于模板的脚本生成
  • /ci-setup
    - 配置检测与缓存
  • /security-scan
    - 提前退出与聚焦区域模式
缓存行为:
  • 缓存位置:
    .claude/cache/playwright-automate/
  • 缓存内容:Playwright安装状态、MCP配置、常见工作流
  • 缓存有效期:直到package.json或MCP配置变更
  • 共享对象:
    /mcp-setup
    /e2e-generate
    /tool-connect
    技能
使用方法:
  • playwright-automate screenshot https://example.com
    - 截图(300-600个Token)
  • playwright-automate pdf https://example.com
    - PDF生成(300-600个Token)
  • playwright-automate test
    - 生成测试脚本(600-1000个Token)
  • playwright-automate scrape https://example.com
    - 爬取脚本(500-900个Token)

Phase 1: Prerequisites Check

阶段1:前置条件检查

bash
#!/bin/bash
bash
#!/bin/bash

Check Playwright installation and setup

检查Playwright安装与设置

check_playwright() { echo "=== Playwright Setup Check ===" echo ""
# Check for Playwright installation
if [ -f "package.json" ]; then
    if grep -q "@playwright/test" package.json; then
        echo "✓ Playwright detected in package.json"
        PLAYWRIGHT_INSTALLED=true
    else
        echo "⚠️  Playwright not found in package.json"
        PLAYWRIGHT_INSTALLED=false
    fi
else
    echo "⚠️  No package.json found"
    PLAYWRIGHT_INSTALLED=false
fi

# Check if Playwright CLI is available
if command -v playwright &> /dev/null; then
    echo "✓ Playwright CLI available"
    playwright --version
else
    echo "⚠️  Playwright CLI not in PATH"
fi

# Check for Playwright MCP server
if [ -f "$HOME/.claude/config.json" ]; then
    if grep -q "playwright" "$HOME/.claude/config.json"; then
        echo "✓ Playwright MCP server configured"
        MCP_CONFIGURED=true
    else
        echo "⚠️  Playwright MCP server not configured"
        MCP_CONFIGURED=false
    fi
fi

echo ""

# Offer installation if needed
if [ "$PLAYWRIGHT_INSTALLED" = false ]; then
    echo "Would you like to install Playwright?"
    echo "  1. npm install --save-dev @playwright/test"
    echo "  2. npx playwright install"
    echo ""
fi

if [ "$MCP_CONFIGURED" = false ]; then
    echo "For MCP integration, run: /mcp-setup playwright"
    echo ""
fi
}
check_playwright
undefined
check_playwright() { echo "=== Playwright设置检查 ===" echo ""
# 检查Playwright安装
if [ -f "package.json" ]; then
    if grep -q "@playwright/test" package.json; then
        echo "✓ 在package.json中检测到Playwright"
        PLAYWRIGHT_INSTALLED=true
    else
        echo "⚠️  在package.json中未找到Playwright"
        PLAYWRIGHT_INSTALLED=false
    fi
else
    echo "⚠️  未找到package.json"
    PLAYWRIGHT_INSTALLED=false
fi

# 检查Playwright CLI是否可用
if command -v playwright &> /dev/null; then
    echo "✓ Playwright CLI可用"
    playwright --version
else
    echo "⚠️  Playwright CLI不在PATH中"
fi

# 检查Playwright MCP服务器
if [ -f "$HOME/.claude/config.json" ]; then
    if grep -q "playwright" "$HOME/.claude/config.json"; then
        echo "✓ Playwright MCP服务器已配置"
        MCP_CONFIGURED=true
    else
        echo "⚠️  Playwright MCP服务器未配置"
        MCP_CONFIGURED=false
    fi
fi

echo ""

# 若需要则提供安装选项
if [ "$PLAYWRIGHT_INSTALLED" = false ]; then
    echo "你是否要安装Playwright?"
    echo "  1. npm install --save-dev @playwright/test"
    echo "  2. npx playwright install"
    echo ""
fi

if [ "$MCP_CONFIGURED" = false ]; then
    echo "如需MCP集成,请运行:/mcp-setup playwright"
    echo ""
fi
}
check_playwright
undefined

Phase 2: Automation Type Detection

阶段2:自动化类型检测

Based on your request, I'll determine the automation workflow:
bash
#!/bin/bash
根据你的请求,我将确定自动化工作流:
bash
#!/bin/bash

Parse automation request

解析自动化请求

parse_automation_request() { local args="$1"
case "$args" in
    *screenshot*|*capture*|*snap*)
        TASK="screenshot"
        ;;
    *pdf*|*print*|*save*)
        TASK="pdf"
        ;;
    *scrape*|*extract*|*data*)
        TASK="scrape"
        ;;
    *test*|*e2e*|*verify*)
        TASK="test"
        ;;
    *form*|*submit*|*fill*)
        TASK="form"
        ;;
    *monitor*|*performance*|*perf*)
        TASK="performance"
        ;;
    *)
        TASK="interactive"
        ;;
esac

echo "Automation task: $TASK"
}
parse_automation_request "$ARGUMENTS"
undefined
parse_automation_request() { local args="$1"
case "$args" in
    *screenshot*|*capture*|*snap*)
        TASK="screenshot"
        ;;
    *pdf*|*print*|*save*)
        TASK="pdf"
        ;;
    *scrape*|*extract*|*data*)
        TASK="scrape"
        ;;
    *test*|*e2e*|*verify*)
        TASK="test"
        ;;
    *form*|*submit*|*fill*)
        TASK="form"
        ;;
    *monitor*|*performance*|*perf*)
        TASK="performance"
        ;;
    *)
        TASK="interactive"
        ;;
esac

echo "自动化任务:$TASK"
}
parse_automation_request "$ARGUMENTS"
undefined

Phase 3: Screenshot Automation

阶段3:截图自动化

Generate automated screenshot workflows:
typescript
// scripts/playwright-screenshot.ts
import { chromium, FullConfig } from '@playwright/test';

async function captureScreenshots(config: ScreenshotConfig) {
  const browser = await chromium.launch({
    headless: true
  });

  const context = await browser.newContext({
    viewport: config.viewport || { width: 1920, height: 1080 }
  });

  const page = await context.newPage();

  try {
    // Navigate to URL
    await page.goto(config.url, { waitUntil: 'networkidle' });

    // Wait for specific element if provided
    if (config.waitForSelector) {
      await page.waitForSelector(config.waitForSelector, { timeout: 10000 });
    }

    // Capture full page screenshot
    if (config.fullPage) {
      await page.screenshot({
        path: config.outputPath || 'screenshot-full.png',
        fullPage: true
      });
      console.log(`✓ Full page screenshot saved: ${config.outputPath}`);
    }

    // Capture specific element
    if (config.elementSelector) {
      const element = page.locator(config.elementSelector);
      await element.screenshot({
        path: config.elementOutputPath || 'screenshot-element.png'
      });
      console.log(`✓ Element screenshot saved: ${config.elementOutputPath}`);
    }

    // Capture multiple viewports (responsive)
    if (config.responsive) {
      const viewports = [
        { name: 'mobile', width: 375, height: 667 },
        { name: 'tablet', width: 768, height: 1024 },
        { name: 'desktop', width: 1920, height: 1080 }
      ];

      for (const viewport of viewports) {
        await page.setViewportSize({ width: viewport.width, height: viewport.height });
        await page.screenshot({
          path: `screenshot-${viewport.name}.png`
        });
        console.log(`${viewport.name} screenshot saved`);
      }
    }

  } finally {
    await context.close();
    await browser.close();
  }
}

// Configuration interface
interface ScreenshotConfig {
  url: string;
  viewport?: { width: number; height: number };
  waitForSelector?: string;
  fullPage?: boolean;
  elementSelector?: string;
  outputPath?: string;
  elementOutputPath?: string;
  responsive?: boolean;
}

// Example usage
const config: ScreenshotConfig = {
  url: process.env.URL || 'http://localhost:3000',
  fullPage: true,
  responsive: true,
  outputPath: 'screenshots/homepage.png'
};

captureScreenshots(config).catch(console.error);
Bash wrapper for easy execution:
bash
#!/bin/bash
生成自动化截图工作流:
typescript
// scripts/playwright-screenshot.ts
import { chromium, FullConfig } from '@playwright/test';

async function captureScreenshots(config: ScreenshotConfig) {
  const browser = await chromium.launch({
    headless: true
  });

  const context = await browser.newContext({
    viewport: config.viewport || { width: 1920, height: 1080 }
  });

  const page = await context.newPage();

  try {
    // 导航到URL
    await page.goto(config.url, { waitUntil: 'networkidle' });

    // 若提供则等待特定元素
    if (config.waitForSelector) {
      await page.waitForSelector(config.waitForSelector, { timeout: 10000 });
    }

    // 捕获整页截图
    if (config.fullPage) {
      await page.screenshot({
        path: config.outputPath || 'screenshot-full.png',
        fullPage: true
      });
      console.log(`✓ 整页截图已保存:${config.outputPath}`);
    }

    // 捕获特定元素
    if (config.elementSelector) {
      const element = page.locator(config.elementSelector);
      await element.screenshot({
        path: config.elementOutputPath || 'screenshot-element.png'
      });
      console.log(`✓ 元素截图已保存:${config.elementOutputPath}`);
    }

    // 捕获多视口截图(响应式)
    if (config.responsive) {
      const viewports = [
        { name: 'mobile', width: 375, height: 667 },
        { name: 'tablet', width: 768, height: 1024 },
        { name: 'desktop', width: 1920, height: 1080 }
      ];

      for (const viewport of viewports) {
        await page.setViewportSize({ width: viewport.width, height: viewport.height });
        await page.screenshot({
          path: `screenshot-${viewport.name}.png`
        });
        console.log(`${viewport.name}截图已保存`);
      }
    }

  } finally {
    await context.close();
    await browser.close();
  }
}

// 配置接口
interface ScreenshotConfig {
  url: string;
  viewport?: { width: number; height: number };
  waitForSelector?: string;
  fullPage?: boolean;
  elementSelector?: string;
  outputPath?: string;
  elementOutputPath?: string;
  responsive?: boolean;
}

// 示例用法
const config: ScreenshotConfig = {
  url: process.env.URL || 'http://localhost:3000',
  fullPage: true,
  responsive: true,
  outputPath: 'screenshots/homepage.png'
};

captureScreenshots(config).catch(console.error);
便于执行的Bash包装器:
bash
#!/bin/bash

screenshot-automation.sh

screenshot-automation.sh

screenshot_page() { local url="$1" local output="${2:-screenshot.png}"
echo "Capturing screenshot of: $url"

npx playwright screenshot \
    --browser chromium \
    --full-page \
    --output "$output" \
    "$url"

if [ $? -eq 0 ]; then
    echo "✓ Screenshot saved: $output"
    echo "  Size: $(du -h "$output" | cut -f1)"
else
    echo "❌ Screenshot failed"
    exit 1
fi
}
screenshot_page() { local url="$1" local output="${2:-screenshot.png}"
echo "正在捕获截图:$url"

npx playwright screenshot \
    --browser chromium \
    --full-page \
    --output "$output" \
    "$url"

if [ $? -eq 0 ]; then
    echo "✓ 截图已保存:$output"
    echo "  大小:$(du -h "$output" | cut -f1)"
else
    echo "❌ 截图失败"
    exit 1
fi
}

Multi-viewport capture

多视口捕获

screenshot_responsive() { local url="$1" local base_name="${2:-screenshot}"
echo "Capturing responsive screenshots..."

# Mobile
npx playwright screenshot \
    --browser chromium \
    --viewport-size 375,667 \
    --output "${base_name}-mobile.png" \
    "$url"

# Tablet
npx playwright screenshot \
    --browser chromium \
    --viewport-size 768,1024 \
    --output "${base_name}-tablet.png" \
    "$url"

# Desktop
npx playwright screenshot \
    --browser chromium \
    --viewport-size 1920,1080 \
    --full-page \
    --output "${base_name}-desktop.png" \
    "$url"

echo "✓ Responsive screenshots complete"
ls -lh ${base_name}-*.png
}
screenshot_responsive() { local url="$1" local base_name="${2:-screenshot}"
echo "正在捕获响应式截图..."

# 移动端
npx playwright screenshot \
    --browser chromium \
    --viewport-size 375,667 \
    --output "${base_name}-mobile.png" \
    "$url"

# 平板端
npx playwright screenshot \
    --browser chromium \
    --viewport-size 768,1024 \
    --output "${base_name}-tablet.png" \
    "$url"

# 桌面端
npx playwright screenshot \
    --browser chromium \
    --viewport-size 1920,1080 \
    --full-page \
    --output "${base_name}-desktop.png" \
    "$url"

echo "✓ 响应式截图完成"
ls -lh ${base_name}-*.png
}

Execute based on arguments

根据参数执行

case "$1" in single) screenshot_page "$2" "$3" ;; responsive) screenshot_responsive "$2" "$3" ;; *) echo "Usage: $0 {single|responsive} <url> [output]" ;; esac
undefined
case "$1" in single) screenshot_page "$2" "$3" ;; responsive) screenshot_responsive "$2" "$3" ;; *) echo "用法:$0 {single|responsive} <url> [output]" ;; esac
undefined

Phase 4: PDF Generation

阶段4:PDF生成

Generate PDFs from web pages:
typescript
// scripts/playwright-pdf.ts
import { chromium } from '@playwright/test';

async function generatePDF(config: PDFConfig) {
  const browser = await chromium.launch({ headless: true });
  const context = await browser.newContext();
  const page = await context.newPage();

  try {
    await page.goto(config.url, { waitUntil: 'networkidle' });

    // Wait for dynamic content
    if (config.waitForSelector) {
      await page.waitForSelector(config.waitForSelector);
    }

    // Add delay for full rendering
    if (config.delayMs) {
      await page.waitForTimeout(config.delayMs);
    }

    // Generate PDF
    await page.pdf({
      path: config.outputPath || 'output.pdf',
      format: config.format || 'A4',
      printBackground: true,
      margin: config.margin || {
        top: '20px',
        right: '20px',
        bottom: '20px',
        left: '20px'
      },
      displayHeaderFooter: config.headerFooter || false,
      headerTemplate: config.headerTemplate,
      footerTemplate: config.footerTemplate
    });

    console.log(`✓ PDF generated: ${config.outputPath}`);

  } finally {
    await context.close();
    await browser.close();
  }
}

interface PDFConfig {
  url: string;
  outputPath?: string;
  format?: 'Letter' | 'Legal' | 'A4' | 'A3';
  waitForSelector?: string;
  delayMs?: number;
  margin?: { top: string; right: string; bottom: string; left: string };
  headerFooter?: boolean;
  headerTemplate?: string;
  footerTemplate?: string;
}

// CLI execution
const url = process.argv[2] || 'http://localhost:3000';
const output = process.argv[3] || 'output.pdf';

generatePDF({ url, outputPath: output }).catch(console.error);
从网页生成PDF:
typescript
// scripts/playwright-pdf.ts
import { chromium } from '@playwright/test';

async function generatePDF(config: PDFConfig) {
  const browser = await chromium.launch({ headless: true });
  const context = await browser.newContext();
  const page = await context.newPage();

  try {
    await page.goto(config.url, { waitUntil: 'networkidle' });

    // 等待动态内容
    if (config.waitForSelector) {
      await page.waitForSelector(config.waitForSelector);
    }

    // 添加延迟以完成渲染
    if (config.delayMs) {
      await page.waitForTimeout(config.delayMs);
    }

    // 生成PDF
    await page.pdf({
      path: config.outputPath || 'output.pdf',
      format: config.format || 'A4',
      printBackground: true,
      margin: config.margin || {
        top: '20px',
        right: '20px',
        bottom: '20px',
        left: '20px'
      },
      displayHeaderFooter: config.headerFooter || false,
      headerTemplate: config.headerTemplate,
      footerTemplate: config.footerTemplate
    });

    console.log(`✓ PDF已生成:${config.outputPath}`);

  } finally {
    await context.close();
    await browser.close();
  }
}

interface PDFConfig {
  url: string;
  outputPath?: string;
  format?: 'Letter' | 'Legal' | 'A4' | 'A3';
  waitForSelector?: string;
  delayMs?: number;
  margin?: { top: string; right: string; bottom: string; left: string };
  headerFooter?: boolean;
  headerTemplate?: string;
  footerTemplate?: string;
}

// CLI执行
const url = process.argv[2] || 'http://localhost:3000';
const output = process.argv[3] || 'output.pdf';

generatePDF({ url, outputPath: output }).catch(console.error);

Phase 5: Web Scraping

阶段5:网页爬取

Automated data extraction:
typescript
// scripts/playwright-scrape.ts
import { chromium } from '@playwright/test';
import * as fs from 'fs';

async function scrapeData(config: ScrapeConfig) {
  const browser = await chromium.launch({ headless: true });
  const context = await browser.newContext();
  const page = await context.newPage();

  try {
    await page.goto(config.url, { waitUntil: 'networkidle' });

    // Wait for content
    await page.waitForSelector(config.contentSelector, { timeout: 10000 });

    // Extract data
    const data = await page.evaluate((selectors) => {
      const results: any = {};

      Object.entries(selectors).forEach(([key, selector]) => {
        const elements = document.querySelectorAll(selector as string);
        results[key] = Array.from(elements).map(el => ({
          text: el.textContent?.trim(),
          html: el.innerHTML,
          attributes: Array.from(el.attributes).reduce((acc, attr) => {
            acc[attr.name] = attr.value;
            return acc;
          }, {} as Record<string, string>)
        }));
      });

      return results;
    }, config.selectors);

    // Save results
    const output = {
      url: config.url,
      timestamp: new Date().toISOString(),
      data
    };

    fs.writeFileSync(
      config.outputPath || 'scraped-data.json',
      JSON.stringify(output, null, 2)
    );

    console.log(`✓ Data scraped and saved: ${config.outputPath}`);
    console.log(`  Extracted ${Object.keys(data).length} data sets`);

  } finally {
    await context.close();
    await browser.close();
  }
}

interface ScrapeConfig {
  url: string;
  contentSelector: string;
  selectors: Record<string, string>;
  outputPath?: string;
}

// Example usage
const config: ScrapeConfig = {
  url: process.argv[2] || 'http://localhost:3000',
  contentSelector: 'main',
  selectors: {
    titles: 'h1, h2, h3',
    paragraphs: 'p',
    links: 'a[href]',
    images: 'img[src]'
  },
  outputPath: 'scraped-data.json'
};

scrapeData(config).catch(console.error);
自动化数据提取:
typescript
// scripts/playwright-scrape.ts
import { chromium } from '@playwright/test';
import * as fs from 'fs';

async function scrapeData(config: ScrapeConfig) {
  const browser = await chromium.launch({ headless: true });
  const context = await browser.newContext();
  const page = await context.newPage();

  try {
    await page.goto(config.url, { waitUntil: 'networkidle' });

    // 等待内容加载
    await page.waitForSelector(config.contentSelector, { timeout: 10000 });

    // 提取数据
    const data = await page.evaluate((selectors) => {
      const results: any = {};

      Object.entries(selectors).forEach(([key, selector]) => {
        const elements = document.querySelectorAll(selector as string);
        results[key] = Array.from(elements).map(el => ({
          text: el.textContent?.trim(),
          html: el.innerHTML,
          attributes: Array.from(el.attributes).reduce((acc, attr) => {
            acc[attr.name] = attr.value;
            return acc;
          }, {} as Record<string, string>)
        }));
      });

      return results;
    }, config.selectors);

    // 保存结果
    const output = {
      url: config.url,
      timestamp: new Date().toISOString(),
      data
    };

    fs.writeFileSync(
      config.outputPath || 'scraped-data.json',
      JSON.stringify(output, null, 2)
    );

    console.log(`✓ 数据已爬取并保存:${config.outputPath}`);
    console.log(`  提取了${Object.keys(data).length}组数据`);

  } finally {
    await context.close();
    await browser.close();
  }
}

interface ScrapeConfig {
  url: string;
  contentSelector: string;
  selectors: Record<string, string>;
  outputPath?: string;
}

// 示例用法
const config: ScrapeConfig = {
  url: process.argv[2] || 'http://localhost:3000',
  contentSelector: 'main',
  selectors: {
    titles: 'h1, h2, h3',
    paragraphs: 'p',
    links: 'a[href]',
    images: 'img[src]'
  },
  outputPath: 'scraped-data.json'
};

scrapeData(config).catch(console.error);

Phase 6: Form Automation

阶段6:表单自动化

Automated form filling and submission:
typescript
// scripts/playwright-form.ts
import { chromium } from '@playwright/test';

async function automateForm(config: FormConfig) {
  const browser = await chromium.launch({
    headless: config.headless !== false
  });

  const context = await browser.newContext();
  const page = await context.newPage();

  try {
    await page.goto(config.url, { waitUntil: 'networkidle' });

    // Fill form fields
    for (const [selector, value] of Object.entries(config.fields)) {
      await page.fill(selector, String(value));
      console.log(`✓ Filled field: ${selector}`);
    }

    // Handle checkboxes
    if (config.checkboxes) {
      for (const selector of config.checkboxes) {
        await page.check(selector);
        console.log(`✓ Checked: ${selector}`);
      }
    }

    // Handle radio buttons
    if (config.radioButtons) {
      for (const selector of config.radioButtons) {
        await page.check(selector);
        console.log(`✓ Selected radio: ${selector}`);
      }
    }

    // Handle dropdowns
    if (config.selects) {
      for (const [selector, value] of Object.entries(config.selects)) {
        await page.selectOption(selector, value);
        console.log(`✓ Selected option: ${selector} = ${value}`);
      }
    }

    // Take screenshot before submit
    if (config.screenshotBeforeSubmit) {
      await page.screenshot({ path: 'form-before-submit.png' });
    }

    // Submit form
    if (config.submitSelector) {
      await page.click(config.submitSelector);
      await page.waitForLoadState('networkidle');
      console.log('✓ Form submitted');

      // Take screenshot after submit
      if (config.screenshotAfterSubmit) {
        await page.screenshot({ path: 'form-after-submit.png' });
      }

      // Verify success
      if (config.successSelector) {
        const success = await page.locator(config.successSelector).isVisible();
        if (success) {
          console.log('✓ Form submission successful');
        } else {
          console.log('⚠️  Success indicator not found');
        }
      }
    }

  } finally {
    await context.close();
    await browser.close();
  }
}

interface FormConfig {
  url: string;
  fields: Record<string, string | number>;
  checkboxes?: string[];
  radioButtons?: string[];
  selects?: Record<string, string>;
  submitSelector?: string;
  successSelector?: string;
  screenshotBeforeSubmit?: boolean;
  screenshotAfterSubmit?: boolean;
  headless?: boolean;
}

// Example
const config: FormConfig = {
  url: 'http://localhost:3000/contact',
  fields: {
    'input[name="name"]': 'Test User',
    'input[name="email"]': 'test@example.com',
    'textarea[name="message"]': 'This is an automated test message'
  },
  checkboxes: ['input[name="newsletter"]'],
  submitSelector: 'button[type="submit"]',
  successSelector: '.success-message',
  screenshotAfterSubmit: true
};

automateForm(config).catch(console.error);
自动化表单填写与提交:
typescript
// scripts/playwright-form.ts
import { chromium } from '@playwright/test';

async function automateForm(config: FormConfig) {
  const browser = await chromium.launch({
    headless: config.headless !== false
  });

  const context = await browser.newContext();
  const page = await context.newPage();

  try {
    await page.goto(config.url, { waitUntil: 'networkidle' });

    // 填写表单字段
    for (const [selector, value] of Object.entries(config.fields)) {
      await page.fill(selector, String(value));
      console.log(`✓ 已填写字段:${selector}`);
    }

    // 处理复选框
    if (config.checkboxes) {
      for (const selector of config.checkboxes) {
        await page.check(selector);
        console.log(`✓ 已勾选:${selector}`);
      }
    }

    // 处理单选按钮
    if (config.radioButtons) {
      for (const selector of config.radioButtons) {
        await page.check(selector);
        console.log(`✓ 已选择单选按钮:${selector}`);
      }
    }

    // 处理下拉菜单
    if (config.selects) {
      for (const [selector, value] of Object.entries(config.selects)) {
        await page.selectOption(selector, value);
        console.log(`✓ 已选择选项:${selector} = ${value}`);
      }
    }

    // 提交前截图
    if (config.screenshotBeforeSubmit) {
      await page.screenshot({ path: 'form-before-submit.png' });
    }

    // 提交表单
    if (config.submitSelector) {
      await page.click(config.submitSelector);
      await page.waitForLoadState('networkidle');
      console.log('✓ 表单已提交');

      // 提交后截图
      if (config.screenshotAfterSubmit) {
        await page.screenshot({ path: 'form-after-submit.png' });
      }

      // 验证提交成功
      if (config.successSelector) {
        const success = await page.locator(config.successSelector).isVisible();
        if (success) {
          console.log('✓ 表单提交成功');
        } else {
          console.log('⚠️  未找到成功提示');
        }
      }
    }

  } finally {
    await context.close();
    await browser.close();
  }
}

interface FormConfig {
  url: string;
  fields: Record<string, string | number>;
  checkboxes?: string[];
  radioButtons?: string[];
  selects?: Record<string, string>;
  submitSelector?: string;
  successSelector?: string;
  screenshotBeforeSubmit?: boolean;
  screenshotAfterSubmit?: boolean;
  headless?: boolean;
}

// 示例
const config: FormConfig = {
  url: 'http://localhost:3000/contact',
  fields: {
    'input[name="name"]': 'Test User',
    'input[name="email"]': 'test@example.com',
    'textarea[name="message"]': '这是一条自动化测试消息'
  },
  checkboxes: ['input[name="newsletter"]'],
  submitSelector: 'button[type="submit"]',
  successSelector: '.success-message',
  screenshotAfterSubmit: true
};

automateForm(config).catch(console.error);

Phase 7: Performance Monitoring

阶段7:性能监控

Monitor page performance metrics:
typescript
// scripts/playwright-performance.ts
import { chromium, devices } from '@playwright/test';

async function measurePerformance(url: string) {
  const browser = await chromium.launch({ headless: true });
  const context = await browser.newContext(devices['Desktop Chrome']);
  const page = await context.newPage();

  try {
    // Start performance monitoring
    await page.goto(url, { waitUntil: 'networkidle' });

    // Collect performance metrics
    const metrics = await page.evaluate(() => {
      const perfData = performance.getEntriesByType('navigation')[0] as PerformanceNavigationTiming;
      const paintMetrics = performance.getEntriesByType('paint');

      return {
        dns: perfData.domainLookupEnd - perfData.domainLookupStart,
        tcp: perfData.connectEnd - perfData.connectStart,
        request: perfData.responseStart - perfData.requestStart,
        response: perfData.responseEnd - perfData.responseStart,
        dom: perfData.domContentLoadedEventEnd - perfData.domContentLoadedEventStart,
        load: perfData.loadEventEnd - perfData.loadEventStart,
        total: perfData.loadEventEnd - perfData.fetchStart,
        firstPaint: paintMetrics.find(m => m.name === 'first-paint')?.startTime || 0,
        firstContentfulPaint: paintMetrics.find(m => m.name === 'first-contentful-paint')?.startTime || 0
      };
    });

    // Web Vitals
    const vitals = await page.evaluate(() => {
      return new Promise((resolve) => {
        let lcp = 0;
        let fid = 0;
        let cls = 0;

        // Largest Contentful Paint
        new PerformanceObserver((list) => {
          const entries = list.getEntries();
          const lastEntry = entries[entries.length - 1] as any;
          lcp = lastEntry.renderTime || lastEntry.loadTime;
        }).observe({ entryTypes: ['largest-contentful-paint'] });

        // Cumulative Layout Shift
        new PerformanceObserver((list) => {
          for (const entry of list.getEntries()) {
            if (!(entry as any).hadRecentInput) {
              cls += (entry as any).value;
            }
          }
        }).observe({ entryTypes: ['layout-shift'] });

        setTimeout(() => {
          resolve({ lcp, fid, cls });
        }, 5000);
      });
    });

    console.log('=== Performance Metrics ===');
    console.log('');
    console.log('Navigation Timing:');
    console.log(`  DNS Lookup:     ${metrics.dns.toFixed(2)}ms`);
    console.log(`  TCP Connect:    ${metrics.tcp.toFixed(2)}ms`);
    console.log(`  Request:        ${metrics.request.toFixed(2)}ms`);
    console.log(`  Response:       ${metrics.response.toFixed(2)}ms`);
    console.log(`  DOM Processing: ${metrics.dom.toFixed(2)}ms`);
    console.log(`  Load Event:     ${metrics.load.toFixed(2)}ms`);
    console.log(`  Total:          ${metrics.total.toFixed(2)}ms`);
    console.log('');
    console.log('Paint Metrics:');
    console.log(`  First Paint:              ${metrics.firstPaint.toFixed(2)}ms`);
    console.log(`  First Contentful Paint:   ${metrics.firstContentfulPaint.toFixed(2)}ms`);
    console.log('');
    console.log('Web Vitals:');
    console.log(`  LCP (Largest Contentful Paint): ${(vitals as any).lcp.toFixed(2)}ms`);
    console.log(`  CLS (Cumulative Layout Shift):  ${(vitals as any).cls.toFixed(4)}`);

    // Performance assessment
    console.log('');
    console.log('Assessment:');
    if (metrics.total < 3000) {
      console.log('  ✓ Excellent load time');
    } else if (metrics.total < 5000) {
      console.log('  ⚠️  Good load time, room for improvement');
    } else {
      console.log('  ❌ Slow load time, optimization needed');
    }

  } finally {
    await context.close();
    await browser.close();
  }
}

const url = process.argv[2] || 'http://localhost:3000';
measurePerformance(url).catch(console.error);
监控页面性能指标:
typescript
// scripts/playwright-performance.ts
import { chromium, devices } from '@playwright/test';

async function measurePerformance(url: string) {
  const browser = await chromium.launch({ headless: true });
  const context = await browser.newContext(devices['Desktop Chrome']);
  const page = await context.newPage();

  try {
    // 开始性能监控
    await page.goto(url, { waitUntil: 'networkidle' });

    // 收集性能指标
    const metrics = await page.evaluate(() => {
      const perfData = performance.getEntriesByType('navigation')[0] as PerformanceNavigationTiming;
      const paintMetrics = performance.getEntriesByType('paint');

      return {
        dns: perfData.domainLookupEnd - perfData.domainLookupStart,
        tcp: perfData.connectEnd - perfData.connectStart,
        request: perfData.responseStart - perfData.requestStart,
        response: perfData.responseEnd - perfData.responseStart,
        dom: perfData.domContentLoadedEventEnd - perfData.domContentLoadedEventStart,
        load: perfData.loadEventEnd - perfData.loadEventStart,
        total: perfData.loadEventEnd - perfData.fetchStart,
        firstPaint: paintMetrics.find(m => m.name === 'first-paint')?.startTime || 0,
        firstContentfulPaint: paintMetrics.find(m => m.name === 'first-contentful-paint')?.startTime || 0
      };
    });

    // Web Vitals指标
    const vitals = await page.evaluate(() => {
      return new Promise((resolve) => {
        let lcp = 0;
        let fid = 0;
        let cls = 0;

        // 最大内容绘制
        new PerformanceObserver((list) => {
          const entries = list.getEntries();
          const lastEntry = entries[entries.length - 1] as any;
          lcp = lastEntry.renderTime || lastEntry.loadTime;
        }).observe({ entryTypes: ['largest-contentful-paint'] });

        // 累积布局偏移
        new PerformanceObserver((list) => {
          for (const entry of list.getEntries()) {
            if (!(entry as any).hadRecentInput) {
              cls += (entry as any).value;
            }
          }
        }).observe({ entryTypes: ['layout-shift'] });

        setTimeout(() => {
          resolve({ lcp, fid, cls });
        }, 5000);
      });
    });

    console.log('=== 性能指标 ===');
    console.log('');
    console.log('导航计时:');
    console.log(`  DNS查询:     ${metrics.dns.toFixed(2)}ms`);
    console.log(`  TCP连接:    ${metrics.tcp.toFixed(2)}ms`);
    console.log(`  请求发送:        ${metrics.request.toFixed(2)}ms`);
    console.log(` 响应接收:       ${metrics.response.toFixed(2)}ms`);
    console.log(`  DOM处理: ${metrics.dom.toFixed(2)}ms`);
    console.log(` 加载事件:     ${metrics.load.toFixed(2)}ms`);
    console.log(` 总耗时:          ${metrics.total.toFixed(2)}ms`);
    console.log('');
    console.log('绘制指标:');
    console.log(` 首次绘制:              ${metrics.firstPaint.toFixed(2)}ms`);
    console.log(` 首次内容绘制:   ${metrics.firstContentfulPaint.toFixed(2)}ms`);
    console.log('');
    console.log('Web Vitals:');
    console.log(`  LCP(最大内容绘制): ${(vitals as any).lcp.toFixed(2)}ms`);
    console.log(`  CLS(累积布局偏移):  ${(vitals as any).cls.toFixed(4)}`);

    // 性能评估
    console.log('');
    console.log('评估结果:');
    if (metrics.total < 3000) {
      console.log('  ✓ 加载速度极佳');
    } else if (metrics.total < 5000) {
      console.log('  ⚠️  加载速度良好,仍有优化空间');
    } else {
      console.log('  ❌ 加载速度缓慢,需要优化');
    }

  } finally {
    await context.close();
    await browser.close();
  }
}

const url = process.argv[2] || 'http://localhost:3000';
measurePerformance(url).catch(console.error);

Phase 8: Package Scripts

阶段8:包脚本

Add automation scripts to package.json:
bash
#!/bin/bash
将自动化脚本添加到package.json:
bash
#!/bin/bash

Add Playwright automation scripts to package.json

将Playwright自动化脚本添加到package.json

add_automation_scripts() { echo "Add these scripts to your package.json:" echo "" cat << 'EOF' "scripts": { "playwright:screenshot": "ts-node scripts/playwright-screenshot.ts", "playwright:pdf": "ts-node scripts/playwright-pdf.ts", "playwright:scrape": "ts-node scripts/playwright-scrape.ts", "playwright:form": "ts-node scripts/playwright-form.ts", "playwright:perf": "ts-node scripts/playwright-performance.ts" } EOF echo "" }
add_automation_scripts
undefined
add_automation_scripts() { echo "将以下脚本添加到你的package.json:" echo "" cat << 'EOF' "scripts": { "playwright:screenshot": "ts-node scripts/playwright-screenshot.ts", "playwright:pdf": "ts-node scripts/playwright-pdf.ts", "playwright:scrape": "ts-node scripts/playwright-scrape.ts", "playwright:form": "ts-node scripts/playwright-form.ts", "playwright:perf": "ts-node scripts/playwright-performance.ts" } EOF echo "" }
add_automation_scripts
undefined

Practical Examples

实际示例

Screenshot capture:
bash
/playwright-automate screenshot https://example.com
/playwright-automate screenshot --responsive --output screenshots/
PDF generation:
bash
/playwright-automate pdf https://example.com/docs
/playwright-automate pdf --format A4 --output documentation.pdf
Web scraping:
bash
/playwright-automate scrape https://example.com
/playwright-automate scrape --selector ".products" --output data.json
Form automation:
bash
/playwright-automate form contact-form.config.json
/playwright-automate test-submission
Performance monitoring:
bash
/playwright-automate performance https://example.com
截图捕获:
bash
/playwright-automate screenshot https://example.com
/playwright-automate screenshot --responsive --output screenshots/
PDF生成:
bash
/playwright-automate pdf https://example.com/docs
/playwright-automate pdf --format A4 --output documentation.pdf
网页爬取:
bash
/playwright-automate scrape https://example.com
/playwright-automate scrape --selector ".products" --output data.json
表单自动化:
bash
/playwright-automate form contact-form.config.json
/playwright-automate test-submission
性能监控:
bash
/playwright-automate performance https://example.com

Best Practices

最佳实践

Automation Guidelines:
  • ✅ Use explicit waits (waitForSelector, waitForLoadState)
  • ✅ Handle errors gracefully with try-catch
  • ✅ Set reasonable timeouts
  • ✅ Clean up browser instances
  • ✅ Respect robots.txt and rate limits (for scraping)
Anti-Patterns:
  • ❌ Hard-coded delays (use waitFor instead)
  • ❌ No error handling
  • ❌ Ignoring GDPR/privacy concerns
  • ❌ Excessive scraping requests
自动化指南:
  • ✅ 使用显式等待(waitForSelector、waitForLoadState)
  • ✅ 使用try-catch优雅处理错误
  • ✅ 设置合理的超时时间
  • ✅ 清理浏览器实例
  • ✅ 遵守robots.txt和速率限制(爬取时)
反模式:
  • ❌ 硬编码延迟(改用waitFor)
  • ❌ 无错误处理
  • ❌ 忽略GDPR/隐私问题
  • ❌ 过度爬取请求

Integration Points

集成点

  • /e2e-generate
    - Generate E2E tests with Playwright
  • /test
    - Run Playwright tests alongside unit tests
  • /mcp-setup
    - Configure Playwright MCP server
  • /ci-setup
    - Add Playwright automation to CI pipeline
  • /e2e-generate
    - 使用Playwright生成E2E测试
  • /test
    - 与单元测试一起运行Playwright测试
  • /mcp-setup
    - 配置Playwright MCP服务器
  • /ci-setup
    - 将Playwright自动化添加到CI流水线

What I'll Actually Do

我实际会执行的操作

  1. Detect setup - Check Playwright installation
  2. Understand task - Determine automation type
  3. Generate scripts - Create TypeScript automation code
  4. Execute safely - Run with proper error handling
  5. Document results - Provide clear output and logs
Important: I will NEVER:
  • Scrape sites without respecting robots.txt
  • Automate without rate limiting
  • Ignore privacy and security concerns
  • Add AI attribution
All browser automation will be safe, ethical, and well-documented.
Credits: Based on Playwright browser automation best practices and MCP Playwright server integration patterns.
  1. 检测设置 - 检查Playwright安装情况
  2. 理解任务 - 确定自动化类型
  3. 生成脚本 - 创建TypeScript自动化代码
  4. 安全执行 - 带适当错误处理的运行
  5. 记录结果 - 提供清晰的输出和日志
重要提示: 我绝不会:
  • 在不遵守robots.txt的情况下爬取网站
  • 不进行速率限制的自动化
  • 忽略隐私和安全问题
  • 添加AI署名
所有浏览器自动化都将是安全、合规且有完善文档的。
致谢: 基于Playwright浏览器自动化最佳实践和MCP Playwright服务器集成模式。