开发 AI Agent 时的浏览器自动化方案探索
本文介绍的是 Bright Data 的 Browser API(浏览器自动化 API),一个云端浏览器解决方案
最近在做一个项目,需要让 AI 自动完成一些网页操作:搜索资料、提取信息、填写表单等。一开始觉得应该不难,用 Puppeteer 或 Selenium 就能搞定。但真正动手后才发现,在生产环境中要让浏览器自动化稳定运行,远比想象中复杂。
graph LR
A[AI Agent 启动] --> B[打开浏览器]
B --> C[搜索关键词]
C --> D[分析搜索结果]
D --> E[点击目标链接]
E --> F[提取页面信息]
F --> G{需要更多信息?}
G -->|是| H[填写表单]
G -->|否| J[完成任务]
H --> I[提交表单]
I --> F
style A fill:#e1f5ff
style J fill:#d4edda
style G fill:#fff3cd
遇到的第一个问题:反爬机制
最初的方案很简单:用 Puppeteer 写个脚本,自动访问目标网站。本地测试完全正常,但部署到服务器上运行几次后就出问题了。
第一次是验证码。很多网站会检测到"异常访问",弹出"请验证您是人类"的提示。一开始以为是访问频率太高,降低频率后,验证码依然频繁出现。
后来发现问题出在浏览器指纹上。无头浏览器(headless browser)有很多特征可以被识别:
navigator.webdriver属性为 true- 缺少某些 WebGL 相关的 API
- Chrome DevTools Protocol 的痕迹
- window 对象上的某些属性缺失
反爬系统会检测这些特征,一旦发现是自动化程序,就触发验证码或直接拒绝访问。
graph TD
A[访问网站] --> B{反爬检测}
B -->|检测浏览器指纹| C{navigator.webdriver?}
B -->|检测行为特征| D{访问频率异常?}
B -->|检测环境| E{缺少WebGL等API?}
C -->|是| F[🚫 触发验证码]
D -->|是| F
E -->|是| F
C -->|否| G[✅ 正常访问]
D -->|否| G
E -->|否| G
F --> H[需要人工处理]
style F fill:#f8d7da
style G fill:#d4edda
style H fill:#fff3cd
网上有一些规避方案,比如 puppeteer-extra-plugin-stealth 插件,可以隐藏部分特征。我试过,确实有一定效果,但不是万能的。有些网站的检测机制更复杂,经常需要调整对抗策略。而且这些插件的维护也是个问题,网站更新检测逻辑后,插件可能就失效了。
第二个问题:IP 管理
为了避免单个 IP 被封,我买了一批代理。但代理也带来了新的麻烦。
graph TD
A[需要使用代理] --> B[购买代理服务]
B --> C{代理质量检测}
C -->|便宜数据中心代理| D[❌ 经常被拉黑]
C -->|住宅代理| E[✅ 质量好但贵]
E --> F[配置代理池]
F --> G[实现轮换逻辑]
G --> H{什么时候换?}
H -->|定时换| I[可能触发风控]
H -->|失败后换| J[频率不可控]
G --> K[定期检测可用性]
K --> L[剔除失效代理]
L --> M[补充新代理]
M --> N[还要考虑地理位置]
N --> O[😫 维护成本很高]
style D fill:#f8d7da
style E fill:#fff3cd
style O fill:#f8d7da
首先是代理质量。便宜的数据中心代理经常被网站拉黑,连接成功率很低。我试过几家服务商,质量都不太稳定。住宅代理好一些,但费用也高不少。
其次是轮换逻辑。什么时候换 IP?请求失败后换还是定时换?换得太频繁,有些网站会觉得异常;不换,又容易被封。不同网站的策略不一样,需要分别调试。
还有代理池的维护。要定期检测代理的可用性,剔除失效的,补充新的。这些都需要额外的代码和定时任务。
代理的地理位置也是个问题。有些网站会根据 IP 归属地返回不同内容,或者限制某些地区访问。需要针对不同任务选择合适的代理地区。
第三个问题:规模化运行
一开始只有几个任务,单机跑几个浏览器实例就够了。但后来任务量增加,需要几十甚至上百个并发。
浏览器很吃资源。Chrome 一个实例就要几百 MB 内存,10 个实例就是好几个 GB。CPU 占用也不低,页面渲染、JavaScript 执行都需要计算资源。
我试过用轻量级的 headless 模式,禁用图片加载等优化手段,但效果有限。服务器配置不够的话,要么加机器,要么减少并发数。
会话管理也是个问题。AI Agent 需要保持上下文:登录状态、浏览历史、Cookie 等。多个实例之间要做好数据隔离,避免互相干扰。如果实例崩溃了,还要能恢复会话状态。
横向扩展就更复杂了。单机扛不住,就要多台机器。但多台机器怎么协调?任务怎么分配?状态怎么同步?基本要搭一套完整的分布式系统。
AI Agent 的特殊需求
传统爬虫通常是"请求-响应"模式:发一个 HTTP 请求,拿到页面内容就结束了。但 AI Agent 不一样。
它需要像人一样操作网页:
- 先搜索一个关键词
- 根据搜索结果点击某个链接
- 在新页面填写表单
- 提交后等待结果
- 根据结果决定下一步操作
这是一个多步骤、有状态的交互流程。每一步都依赖前面的操作,需要保持会话连续性。
另外,AI 的决策是动态的。它可能根据页面内容临时调整策略,比如看到某个按钮就点击,没看到就跳过。这种动态交互,用传统的爬虫脚本很难实现。
云端浏览器方案
在寻找解决方案时,我了解到 Bright Data 有一个叫 Browser API 的服务(也叫 Scraping Browser)。简单说,就是把浏览器放在云端运行,通过 API 来控制。
这个思路其实不新。之前也有类似的"浏览器即服务"产品,比如 BrowserStack、Sauce Labs 等,主要用于自动化测试。但 Browser API 的设计目标不太一样,它更侧重于解决生产环境中的反爬和扩展性问题,特别适合多步骤的数据采集场景。
几个关键特点:
有头浏览器运行
它在云端跑的是完整的浏览器(有 GUI 的),而不是 headless 模式。从网站的角度看,这和真实用户访问没什么区别。浏览器指纹、WebGL、各种 API 的行为都和正常浏览器一致。
这解决了前面说的反爬检测问题。因为它本质上就是一个真实的浏览器,没有那些 headless 的特征。
内置反爬处理
验证码识别、IP 轮换、浏览器指纹管理这些,都在底层自动处理了。不需要自己去对接打码平台,也不需要维护代理池。
据官方介绍,他们维护了一个很大的住宅代理网络,覆盖全球 195 个国家。请求失败时会自动切换 IP 重试,对用户来说是透明的。
验证码处理也是自动的。常见的滑块验证、图片选择等,系统会尝试识别和通过。虽然不是 100% 成功,但成功率比自己实现要高不少。
按需分配资源
需要多少个浏览器实例,直接通过 API 创建就行。不用担心服务器资源不够,也不用提前规划容量。
这对于任务量波动比较大的场景很有用。比如平时只需要几个实例,但某个时间段突然需要几百个,可以临时扩容,用完就释放。
兼容现有工具
支持 Puppeteer、Selenium、Playwright 这些常用框架。现有代码基本不用改,只需要改一下连接方式。
这是我比较看重的一点。如果要用一个新工具,意味着要重新学习 API、重写代码、迁移现有项目。但如果能兼容现有工具,迁移成本就低多了。
实际测试
我拿之前的项目试了一下。原本用 Puppeteer 跑的脚本,验证码触发率比较高,大概每访问 5-10 次就会遇到一次验证码。
换成 Browser API 后,同样的任务,跑了上百次,验证码出现的次数明显减少。具体数字没仔细统计,但感觉降到了 5% 以下。
更重要的是,代码改动很小。原本的 Puppeteer 脚本,只需要把连接方式从本地改成远程 WebSocket 就行了:
// 原来的方式
const browser = await puppeteer.launch();
// 改成远程连接(使用 Browser API)
const AUTH = 'USERNAME:PASSWORD'; // 从控制台获取你的凭证
const browser = await puppeteer.connect({
browserWSEndpoint: `wss://${AUTH}@brd.superproxy.io:9222`,
});
// 后面的代码完全不变
const page = await browser.newPage();
await page.goto('https://example.com');
await page.click('#some-button');
// ...
如果用 Selenium,也类似。只需要改一下 WebDriver 的连接地址:
from selenium import webdriver
from selenium.webdriver.chromium.remote_connection import ChromiumRemoteConnection
# 连接到远程浏览器(使用 Browser API)
AUTH = 'USERNAME:PASSWORD' # 从控制台获取你的凭证
sbr_webdriver = f'https://{AUTH}@brd.superproxy.io:9515'
connection = ChromiumRemoteConnection(sbr_webdriver, 'goog', 'chrome')
# 后面的代码不变
with webdriver.Remote(connection, options=webdriver.ChromeOptions()) as driver:
driver.get('https://example.com')
driver.find_element(By.ID, 'some-button').click()
# ...
会话管理的限制
在实际使用中,需要注意 Browser API 的一些会话限制。根据官方文档:
单次导航限制
每个浏览器会话只允许一次"初始导航"(initial navigation)。这个初始导航指的是第一次用 page.goto() 加载目标网站。
之后,你可以在同一个会话中自由地点击、滚动、填表单等操作,但如果要开始一个新的抓取任务(即使是同一个网站),需要创建新的会话。
超时限制
- 空闲超时:如果会话5分钟没有活动,会自动断开
- 最大时长:单个会话最多维持30分钟
这些限制主要是为了防止资源浪费。在设计任务时需要考虑到这一点,把长时间的任务拆分成多个会话,或者确保会话中持续有操作。
会话保持
AI Agent 的另一个需求是会话保持。比如要完成一个"搜索商品并加入购物车"的任务,需要:
- 访问首页
- 登录账号(保持登录态)
- 搜索商品(在登录态下)
- 点击商品详情(仍然保持登录态)
- 加入购物车
- 查看购物车
这个流程中,每一步都依赖前面的状态。如果用传统的 HTTP 请求方式,需要手动管理 Cookie、Session 等。而且很多网站会检测请求头、Referer 等,一旦不一致就会判定为异常。
在真实的浏览器环境里,这些都是自动处理的。Browser API 支持会话保持,可以维护登录态、浏览历史、Cookie 等状态。代码写起来也很自然:
graph TD
A[启动浏览器会话] --> B[访问首页]
B --> C[登录账号]
C --> D[🔒 登录态已建立]
D --> E[搜索商品]
E --> F[🔒 保持登录态]
F --> G[点击商品详情]
G --> H[🔒 继续保持登录态]
H --> I[加入购物车]
I --> J[🔒 仍然保持登录态]
J --> K[查看购物车]
K --> L[✅ 完成整个流程]
style D fill:#d4edda
style F fill:#d4edda
style H fill:#d4edda
style J fill:#d4edda
style L fill:#cfe2ff
整个过程中,Cookie、Session 等会话状态自动保持,无需手动管理
const AUTH = 'USERNAME:PASSWORD'; // 你的 Browser API 凭证
const browser = await puppeteer.connect({
browserWSEndpoint: `wss://${AUTH}@brd.superproxy.io:9222`
});
const page = await browser.newPage();
// 第一步:登录
await page.goto('https://example.com/login');
await page.type('#username', 'myuser');
await page.type('#password', 'mypass');
await page.click('#submit');
await page.waitForNavigation();
// 第二步:搜索商品(自动保持登录态)
await page.goto('https://example.com/search?q=laptop');
await page.waitForSelector('.product-item');
// 第三步:加入购物车(仍然保持登录态)
await page.click('.product-item:first-child .add-to-cart');
await page.waitForTimeout(1000);
// 第四步:查看购物车
await page.goto('https://example.com/cart');
const cartItems = await page.$$eval('.cart-item', items =>
items.map(item => item.textContent)
);
console.log('购物车内容:', cartItems);
整个流程中,登录态、Cookie、浏览历史都自动保持了,不需要手动处理。
多标签页支持
有时候一个任务需要同时操作多个页面。比如在一个页面搜索,在另一个页面查看详情,再在第三个页面比价。
graph TB
A[同一个浏览器会话] --> B[标签页1: 搜索页]
A --> C[标签页2: 商品详情]
A --> D[标签页3: 比价页]
B --> E[提取商品ID]
C --> F[获取详细信息]
D --> G[获取价格对比]
E --> H{数据汇总}
F --> H
G --> H
H --> I[✅ 综合分析结果]
style A fill:#e1f5ff
style H fill:#fff3cd
style I fill:#d4edda
传统的 HTTP 请求方式很难模拟这种场景。但在浏览器里,这就是普通的多标签页操作:
const AUTH = 'USERNAME:PASSWORD';
const browser = await puppeteer.connect({
browserWSEndpoint: `wss://${AUTH}@brd.superproxy.io:9222`
});
// 打开多个标签页
const page1 = await browser.newPage();
await page1.goto('https://site1.com');
const page2 = await browser.newPage();
await page2.goto('https://site2.com');
const page3 = await browser.newPage();
await page3.goto('https://site3.com');
// 在不同标签页之间切换操作
await page1.click('#some-button');
const data1 = await page1.$eval('#result', el => el.textContent);
await page2.type('#input', data1);
await page2.click('#submit');
// 所有标签页共享同一个浏览器会话
这对于需要关联多个网站数据的 AI Agent 很有用。
地理位置选择
有些网站会根据访问者的 IP 地址返回不同内容。比如电商网站的价格、库存,新闻网站的内容等。
Browser API 可以指定浏览器实例的地理位置。支持全球 195 个国家,可以在代码里灵活切换:
const AUTH = 'USERNAME:PASSWORD';
// 从美国访问
const browserUS = await puppeteer.connect({
browserWSEndpoint: `wss://${AUTH}@brd.superproxy.io:9222?country=us`,
});
// 从日本访问
const browserJP = await puppeteer.connect({
browserWSEndpoint: `wss://${AUTH}@brd.superproxy.io:9222?country=jp`,
});
这对于跨区域的数据采集、价格监控等场景比较有用。
扩展性
前面提到,自己搭建分布式浏览器集群很复杂。用云端方案的好处是,扩展性基本不用操心。
需要 10 个并发,就创建 10 个会话;需要 100 个,就创建 100 个。底层的资源调度、负载均衡都是自动的。
graph LR
A[业务需求] --> B{并发数量}
B -->|10个| C1[创建10个会话]
B -->|100个| C2[创建100个会话]
B -->|1000个| C3[创建1000个会话]
C1 --> D[云端自动分配]
C2 --> D
C3 --> D
D --> E[全球分布式节点]
E --> F[自动负载均衡]
F --> G[任务并行执行]
G --> H[✅ 无需管理服务器]
style B fill:#fff3cd
style D fill:#e1f5ff
style H fill:#d4edda
// 同时启动 50 个任务
const tasks = [];
for (let i = 0; i < 50; i++) {
tasks.push(runTask(i));
}
await Promise.all(tasks);
async function runTask(id) {
const browser = await puppeteer.connect({ browserWSEndpoint: '...' });
const page = await browser.newPage();
// 执行任务...
await browser.close();
}
当然,这会产生相应的费用。但至少不用担心服务器撑不住,也不用半夜起来处理故障。
一些限制
没有完美的方案。Browser API 也有一些限制:
会话限制
每个会话只能有一次初始导航,最长30分钟,空闲5分钟自动断开。对于需要长时间保持同一会话的场景,需要特别设计任务流程。
费用问题
按流量计费,如果任务量很大,费用会比较高。需要在成本和便利性之间权衡。对于低频任务或者预算有限的场景,自建可能更合适。
网络延迟
浏览器在云端运行,每次操作都需要通过网络传输指令和结果。如果对响应时间要求很高,可能不太适合。
不是所有网站都能解决
内置的反爬处理能应对大部分网站,但也不是万能的。极个别的网站可能仍然会检测出来。这种情况下,可能需要额外的对抗策略。
调试不如本地方便
本地运行浏览器的话,可以直接看到浏览器窗口,调试起来很直观。云端浏览器虽然也有截图、录屏等调试手段,但还是没有本地方便。
适用场景
综合来看,Browser API 比较适合这些场景:
AI Agent 自动化任务
需要多步交互、保持会话、动态决策的场景。比如智能客服、自动填表、数据采集等。特别适合需要在同一会话中完成多个交互步骤的任务。
大规模并发任务
需要同时运行几十上百个浏览器实例,自建基础设施成本太高的场景。
对反爬要求高
目标网站的反爬机制比较严格,普通 headless 浏览器容易被封的场景。
快速原型开发
想快速验证一个想法,不想花时间搭建基础设施。或者项目初期,任务量不确定,希望先用起来再说。
相反,如果是这些场景,可能不太适合:
- 任务量很小,偶尔跑几次
- 预算非常有限,必须控制成本
- 对响应时间要求极高(毫秒级)
- 需要极度定制化的浏览器环境
总结
浏览器自动化在 AI Agent 时代变得越来越重要。但要在生产环境稳定运行,需要解决反爬、代理、扩展性等一系列问题。
自己搭建完整的基础设施,对于大多数团队来说成本都比较高。云端浏览器服务提供了一个折中方案:用 API 的方式调用浏览器,底层的复杂性都被封装了。
graph TB
subgraph 传统自建方案
A1[开发者] --> B1[购买服务器]
B1 --> C1[部署浏览器]
C1 --> D1[配置代理池]
D1 --> E1[实现反爬对抗]
E1 --> F1[维护监控]
F1 --> G1[处理故障]
G1 --> H1[扩容优化]
end
subgraph 云端浏览器方案
A2[开发者] --> B2[调用 API]
B2 --> C2[✅ 自动分配浏览器]
C2 --> D2[✅ 自动管理代理]
D2 --> E2[✅ 自动处理反爬]
E2 --> F2[✅ 自动扩展]
F2 --> G2[专注业务逻辑]
end
style G1 fill:#f8d7da
style G2 fill:#d4edda
Browser API 是这个方向上的一个实现。它的核心价值是让开发者可以专注于业务逻辑,而不是花时间对抗反爬、维护代理池、管理服务器。
当然,任何技术方案都有适用场景和成本考量。特别是要注意会话限制(单次导航、30分钟最大时长)对业务流程的影响。重要的是理解自己的需求,在便利性、成本、性能之间找到平衡点。
如果你也在开发 AI Agent 或者做浏览器自动化,遇到类似的问题,可以考虑试试看云端浏览器方案。
如果你对亮数据不熟悉,对里面的一些技术不了解,可以直接点击右下角的 AI亮助理 发起提问
相关资源:
- Browser API 官网 - 产品介绍和快速开始
- 官方技术文档 - 详细的 API 文档和配置说明
- 代码示例 - Puppeteer、Playwright、Selenium 等示例