🌐 OpenClaw 浏览器自动化

发布于 2026-04-14 | 阅读时间 12 分钟

"浏览器是 AI 的眼睛。有了它,Agent 不再只是对着空气说话,而是能真正看到网页、点击按钮、填写表单。"

为什么需要浏览器自动化?

很多网站的数据藏在 JavaScript 渲染后的页面里,传统的 HTTP 请求抓不到。还有些操作——比如登录、下载、截图——必须模拟真实浏览器行为才能完成。

OpenClaw 内置了基于 Playwright 的浏览器自动化能力,让你的 Agent 像真人一样浏览网页。

核心功能介绍

  • 页面导航 - 访问 URL、前进后退、刷新页面
  • 元素交互 - 点击、输入、选择、拖拽
  • 数据采集 - 提取文本、属性、截图
  • 多页面管理 - 处理弹窗、多标签页、iframe
  • 模拟设备 - 模拟手机、平板等不同设备
  • 无头/有头模式 - 后台运行或可视化调试

快速开始

基础网页抓取

const { BrowserTool } = require('openclaw/tools/browser');

async function scrapeArticle(url) {
  const browser = new BrowserTool({
    headless: true,        // 无头模式
    timeout: 30000,        // 30秒超时
    viewport: { width: 1920, height: 1080 }
  });

  try {
    // 打开页面
    const page = await browser.open(url);
    
    // 等待内容加载
    await page.waitForSelector('article');
    
    // 提取数据
    const data = await page.evaluate(() => {
      const article = document.querySelector('article');
      return {
        title: article.querySelector('h1')?.textContent?.trim(),
        content: article.querySelector('.content')?.textContent?.trim(),
        author: article.querySelector('.author')?.textContent?.trim(),
        publishDate: article.querySelector('time')?.getAttribute('datetime')
      };
    });
    
    return data;
    
  } finally {
    await browser.close();
  }
}

// 使用
const article = await scrapeArticle('https://example.com/news/123');
console.log(article.title);

表单自动填写

async function autoFillForm(formUrl, data) {
  const browser = new BrowserTool({ headless: false }); // 有头模式调试用
  
  const page = await browser.open(formUrl);
  
  // 填写表单
  await page.fill('input[name="name"]', data.name);
  await page.fill('input[name="email"]', data.email);
  await page.fill('textarea[name="message"]', data.message);
  
  // 选择下拉框
  await page.selectOption('select[name="category"]', data.category);
  
  // 勾选复选框
  if (data.newsletter) {
    await page.check('input[name="newsletter"]');
  }
  
  // 点击提交
  await Promise.all([
    page.waitForNavigation(),  // 等待页面跳转
    page.click('button[type="submit"]')
  ]);
  
  // 验证结果
  const success = await page.isVisible('.success-message');
  return { success, currentUrl: page.url() };
}

高级技巧

处理动态加载内容

async function scrapeInfiniteScroll(url) {
  const browser = new BrowserTool();
  const page = await browser.open(url);
  
  let items = [];
  let previousHeight = 0;
  
  // 无限滚动页面
  while (true) {
    // 获取当前内容
    const newItems = await page.evaluate(() => {
      return Array.from(document.querySelectorAll('.item')).map(el => ({
        title: el.querySelector('.title')?.textContent,
        link: el.querySelector('a')?.href
      }));
    });
    
    items = [...items, ...newItems];
    
    // 滚动到底部
    await page.evaluate(() => window.scrollTo(0, document.body.scrollHeight));
    
    // 等待新内容加载
    await page.waitForTimeout(2000);
    
    // 检查是否还有更多内容
    const currentHeight = await page.evaluate(() => document.body.scrollHeight);
    if (currentHeight === previousHeight) break;
    previousHeight = currentHeight;
  }
  
  return items;
}

截图与 PDF 生成

async function capturePage(url, outputPath) {
  const browser = new BrowserTool();
  const page = await browser.open(url);
  
  // 等待页面完全加载
  await page.waitForLoadState('networkidle');
  
  // 全页截图
  await page.screenshot({
    path: `${outputPath}.png`,
    fullPage: true
  });
  
  // 生成 PDF
  await page.pdf({
    path: `${outputPath}.pdf`,
    format: 'A4',
    printBackground: true,
    margin: { top: '20px', right: '20px', bottom: '20px', left: '20px' }
  });
  
  return { screenshot: `${outputPath}.png`, pdf: `${outputPath}.pdf` };
}

处理登录和 Cookie

class AuthenticatedScraper {
  constructor() {
    this.browser = new BrowserTool();
    this.cookiesPath = './cookies.json';
  }

  async login(credentials) {
    const page = await this.browser.open('https://example.com/login');
    
    // 填写登录表单
    await page.fill('input[name="username"]', credentials.username);
    await page.fill('input[name="password"]', credentials.password);
    
    // 处理验证码(如果有)
    const hasCaptcha = await page.isVisible('.captcha');
    if (hasCaptcha) {
      // 等待人工处理或使用验证码识别服务
      await page.waitForTimeout(30000);
    }
    
    // 提交登录
    await page.click('button[type="submit"]');
    await page.waitForNavigation();
    
    // 保存 Cookie
    const cookies = await this.browser.context.cookies();
    fs.writeFileSync(this.cookiesPath, JSON.stringify(cookies));
    
    return page.url().includes('/dashboard');
  }

  async scrapeWithAuth(url) {
    // 加载 Cookie
    if (fs.existsSync(this.cookiesPath)) {
      const cookies = JSON.parse(fs.readFileSync(this.cookiesPath));
      await this.browser.context.addCookies(cookies);
    }
    
    const page = await this.browser.open(url);
    
    // 检查是否需要重新登录
    if (page.url().includes('/login')) {
      throw new Error('Cookie 已过期,需要重新登录');
    }
    
    // 提取需要登录才能看到的数据
    const data = await page.evaluate(() => ({
      privateData: document.querySelector('.private-info')?.textContent
    }));
    
    return data;
  }
}

最佳实践

✅ 浏览器自动化原则

  • 延迟等待 - 网络不稳定时适当增加 waitForTimeout
  • 优雅降级 - 某些元素不存在时不应崩溃
  • 资源释放 - 一定要调用 browser.close() 释放资源
  • 错误重试 - 网络超时自动重试,避免偶发失败

⚠️ 避坑指南

  • 不要频繁访问同一网站,容易被封 IP
  • 尊重 robots.txt,不要抓取禁止的内容
  • 动态页面要用 waitForSelector 确保元素加载完成
  • 内存敏感场景及时关闭不用的页面标签

在 Agent Skills 中使用

// skills/web-scraper/skill.json
{
  "name": "smart-web-scraper",
  "description": "智能网页抓取,自动处理 JS 渲染",
  "tools": ["browser"],
  "config": {
    "userAgent": "OpenClawBot/1.0",
    "respectRobotsTxt": true
  }
}

// skills/web-scraper/index.js
module.exports = class WebScraperSkill {
  async execute({ url, selectors, waitFor }) {
    const browser = this.tools.browser;
    
    try {
      const page = await browser.open(url);
      
      // 等待指定元素
      if (waitFor) {
        await page.waitForSelector(waitFor, { timeout: 10000 });
      }
      
      // 抓取数据
      const data = {};
      for (const [key, selector] of Object.entries(selectors)) {
        data[key] = await page.textContent(selector);
      }
      
      return { success: true, data };
      
    } catch (error) {
      return { 
        success: false, 
        error: error.message,
        suggestion: '请检查 URL 是否可访问,选择器是否正确'
      };
    }
  }
};

相关链接