🌐 OpenClaw 浏览器自动化
"浏览器是 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 是否可访问,选择器是否正确'
};
}
}
};