web-form-automation

TotalClaw 作者 totalclaw

使用 Playwright 自动执行 Web 表单交互,包括登录、文件上传、文本输入和表单提交。当用户需要自动化网站交互、将文件上传到 Web 表单、使用文本输入填写表单、单击按钮或向 Web 应用程序提交数据时使用。支持通过 cookie 进行会话管理、压缩图像上传 (webp) 以及适当的事件触发以实现可靠的表单提交。

安装 / 下载方式

TotalClaw CLI推荐
totalclaw skills install shop:totalclaw:totalclaw~flyingzl-web-form-automation
cURL直接下载,无需登录
curl -fsSL https://skills.taituai.com/api/skills/totalclaw%3Atotalclaw~flyingzl-web-form-automation/file -o flyingzl-web-form-automation.md
## 概述(中文)

使用 Playwright 自动执行 Web 表单交互,包括登录、文件上传、文本输入和表单提交。当用户需要自动化网站交互、将文件上传到 Web 表单、使用文本输入填写表单、单击按钮或向 Web 应用程序提交数据时使用。支持通过 cookie 进行会话管理、压缩图像上传 (webp) 以及适当的事件触发以实现可靠的表单提交。

## 原文

# Web Form Automation

Automate web form interactions reliably using Playwright with best practices for session management, file uploads, and form submission.

## Quick Start

```javascript
const { chromium } = require('playwright');

// Basic form automation
const browser = await chromium.launch({ headless: true });
const page = await browser.newPage();
await page.goto('https://example.com/form');

// Upload compressed images
await page.locator('input[type="file"]').setInputFiles('/path/to/image.webp');

// Type text (triggers events properly)
await page.locator('textarea').pressSequentially('Your text', { delay: 30 });

// Submit form
await page.locator('button[type="submit"]').click({ force: true });
```

## Session Management

### Using Browser Session Data

When user provides a JSON file with session data:

```javascript
const sessionData = JSON.parse(fs.readFileSync('session.json', 'utf8'));

// Set cookies before navigating
for (const cookie of sessionData.cookies || []) {
  await context.addCookies([cookie]);
}

// Set localStorage/sessionStorage
await page.evaluate((data) => {
  for (const [k, v] of Object.entries(data.localStorage || {})) {
    localStorage.setItem(k, v);
  }
}, sessionData);
```

## File Upload Best Practices

### Image Compression

Always compress images before upload for reliability:

```bash
# Convert to webp for best compression
convert input.png output.webp

# Or resize if needed
convert input.png -resize 1024x1024 output.webp
```

**Size comparison:**
- Original PNG: ~4MB
- Compressed PNG: ~1MB  
- WebP: ~30-50KB (99% smaller)

### Upload Sequence

```javascript
// 1. Find file inputs
const fileInputs = await page.locator('input[type="file"]').all();

// 2. Upload with waiting time
await fileInputs[0].setInputFiles('/path/to/start.webp');
await page.waitForTimeout(3000); // Wait for upload to process

await fileInputs[1].setInputFiles('/path/to/end.webp');
await page.waitForTimeout(3000);
```

## Text Input Best Practices

### Use pressSequentially, not fill()

❌ **Don't use fill()** - doesn't trigger input events:
```javascript
await textInput.fill('text'); // May not activate submit button
```

✅ **Use pressSequentially()** - simulates real typing:
```javascript
await textInput.pressSequentially('text', { delay: 30 });
```

### Trigger Events Manually (if needed)

```javascript
await page.evaluate(() => {
  const el = document.querySelector('textarea');
  el.dispatchEvent(new Event('input', { bubbles: true }));
  el.dispatchEvent(new Event('change', { bubbles: true }));
});
```

## Button Clicking

### Force Click When Disabled

If button appears disabled but should be clickable:

```javascript
await button.click({ force: true });
```

### Check Button State

```javascript
const isEnabled = await button.isEnabled();
const isVisible = await button.isVisible();
```

## Complete Example: Video Generation Form

```javascript
const { chromium } = require('playwright');
const fs = require('fs');

async function submitVideoForm(sessionFile, startImage, endImage, prompt) {
  const browser = await chromium.launch({ 
    headless: true, 
    args: ['--no-sandbox'] 
  });
  const context = await browser.newContext();
  const page = await context.newPage();
  
  // Load session if provided
  if (fs.existsSync(sessionFile)) {
    const session = JSON.parse(fs.readFileSync(sessionFile, 'utf8'));
    // Set cookies, localStorage...
  }
  
  // Navigate
  await page.goto('https://example.com/video', { 
    waitUntil: 'domcontentloaded' 
  });
  await page.waitForTimeout(3000);
  
  // Upload images (webp compressed)
  const inputs = await page.locator('input[type="file"]').all();
  await inputs[0].setInputFiles(startImage);
  await page.waitForTimeout(3000);
  await inputs[1].setInputFiles(endImage);
  await page.waitForTimeout(3000);
  
  // Select options
  await page.click('text=Seedance 2.0 Fast');
  await page.click('text=15s');
  
  // Type prompt
  const textarea = page.locator('textarea').first();
  await textarea.pressSequentially(prompt, { delay: 30 });
  await page.waitForTimeout(2000);
  
  // Submit
  await page.locator('button[class*="submit"]').click({ force: true });
  
  // Wait and screenshot
  await page.waitForTimeout(5000);
  await page.screenshot({ path: 'result.png' });
  
  await browser.close();
}
```

## Scripts

The `scripts/` directory contains reusable automation scripts:

- `webp-compress.sh` - Convert images to webp format
- `form-submit.js` - Generic form submission template

## Troubleshooting

### Button stays gray/disabled
- Wait longer after file upload (3+ seconds)
- Ensure text input triggers events (use pressSequentially)
- Check if images are still uploading

### Upload times out
- Compress images to webp format first
- Reduce image dimensions if very large

### Form doesn't submit
- Use force: true for click
- Check button selector is correct
- Verify all required fields are filled