资讯动态

基于Gemini与Playwright构建智能浏览器代理:从自动化到认知决策

发布时间:2026/8/9 13:30:46 来源:尧图企业网站定制
1. 项目概述当浏览器学会“思考”最近在折腾一个挺有意思的东西让浏览器自己“动脑子”。听起来有点玄乎简单说就是结合 Google 最新的 Gemini 3.5 大语言模型和 Chrome 开发者工具打造一个能理解页面、自动执行任务的智能代理。这不再是简单的录制回放而是让浏览器具备一定的“认知”和“决策”能力。比如你告诉它“帮我把这个商品列表里价格低于100块且评分高于4.5的都加入购物车”它就能自己分析页面结构找到符合条件的元素并完成点击操作。这个项目的核心就是利用 Gemini 3.5 强大的自然语言理解和代码生成能力来驱动 Chrome DevTools Protocol 实现对浏览器的精准控制。为什么是 Gemini 3.5 和 Chrome DevTools 这个组合首先Gemini 3.5 在代码生成、逻辑推理和上下文理解上表现非常出色尤其是其免费、高频率的 API 调用限额对于个人开发者和小型项目实验非常友好。其次Chrome DevTools Protocol 是控制 Chrome 或 Chromium 内核浏览器的“终极武器”它提供了从导航、DOM 操作到网络请求拦截等几乎所有的底层控制接口。将两者结合相当于给浏览器装上了“大脑”和“神经”使其能理解高级指令并转化为精确的底层操作。这不仅仅是自动化更是迈向“智能体”的一步在数据抓取、自动化测试、网页交互研究乃至日常办公自动化中都有巨大的想象空间。2. 核心架构与工具选型解析2.1 为什么选择 Gemini 3.5 作为“大脑”在众多大模型中选中 Gemini 3.5是经过一番考量的。当前开源和闭源的模型选择很多但构建一个稳定、高效的智能代理模型需要满足几个关键点出色的代码生成能力、稳定的长上下文支持、合理的成本以及便捷的 API 接入。Gemini 3.5 的代码生成能力在多项基准测试中名列前茅这对于将自然语言指令转化为操作浏览器的 JavaScript 或 Python 脚本至关重要。它的上下文窗口足够大能记住我们与它多轮对话中设定的复杂任务规则和页面结构信息。最重要的是其免费 tier 的调用限额每分钟高达 60 次请求对于开发和测试阶段绰绰有余避免了初期投入成本。相比之下一些同等能力的模型 API 调用成本高昂而一些小型开源模型在复杂逻辑推理和指令遵循上又不够稳定。在实际使用中我通过google-generativeai这个官方 Python SDK 进行接入非常方便。你需要做的就是在 Google AI Studio 创建一个 API Key然后就可以开始调用了。模型的响应格式可以设定为json这对于我们后续解析结构化指令比如操作类型、目标元素选择器、等待条件等提供了极大的便利。2.2 Chrome DevTools Protocol浏览器的“遥控器”如果说 Gemini 是大脑那么 CDP 就是连接大脑和浏览器身体的中枢神经。CDP 是一个基于 WebSocket 的协议允许外部工具对 Chrome/Chromium 进行检测、调试和控制。我们熟知的 Chrome 开发者工具本身就是通过 CDP 与浏览器通信的。对于我们的智能代理项目我们不直接使用原始的 WebSocket 连接而是选择一个成熟的客户端库。puppeteer和playwright是两个最主流的选择。它们对 CDP 进行了高级封装提供了更友好、更稳定的 API。Puppeteer由 Chrome 团队维护与 Chrome 浏览器契合度最高API 设计简洁。如果你主要针对 Chrome 环境它是一个非常可靠的选择。Playwright由微软团队开发支持 Chromium、Firefox 和 WebKit 三大内核跨浏览器特性是其最大亮点。它的 API 设计更现代在一些复杂场景如自动等待、网络拦截上可能更顺手。在这个项目中我选择了Playwright。原因在于其更强大的自动等待机制减少了手动编写sleep的需要以及对网络请求更精细的控制能力这在处理现代动态网页时尤其重要。智能代理在操作过程中经常需要等待元素出现、等待网络请求完成Playwright 的内置等待策略能让我们更专注于业务逻辑。2.3 系统工作流设计整个智能代理的核心工作流是一个循环解析指令 - 分析页面 - 生成操作 - 执行反馈。指令接收与解析用户输入自然语言指令如“登录邮箱并查看未读邮件”。系统首先将指令发送给 Gemini 3.5要求其将模糊的指令分解为具体的、可执行的步骤序列。例如输出一个 JSON 数组[{action: navigate, url: mail.example.com}, {action: fill, selector: #username, value: my_email}, ...]。页面上下文获取在执行每个步骤前代理需要通过 Playwright 获取当前页面的“快照”。这个快照不仅仅是截图更重要的是结构化的信息当前 URL、页面标题、以及所有关键交互元素的 CSS 选择器、文本内容、可见状态等。这些信息将被整理成一段清晰的文本描述作为上下文再次喂给 Gemini。动态操作生成将“当前页面快照”和“下一步待执行动作”一起发送给 Gemini。模型需要根据实时页面状态动态调整或细化操作。例如指令是“点击登录按钮”但模型发现页面上有两个可能的按钮一个在页头一个在表单内它就需要结合上下文“你正在登录表单中”选择最可能的那一个并生成精确的 Playwright 操作代码如await page.click(form button[type\submit\])。执行与容错执行生成的代码。这里必须有坚固的容错机制。如果执行失败例如元素未找到、超时需要将错误信息如TimeoutError: Waiting for selector \form button\反馈给 Gemini让它分析失败原因并尝试生成备用方案比如换一个选择器或者先滚动到元素可见区域。这个循环的关键在于Gemini 不仅生成初始计划还在每一步都充当“实时决策者”根据浏览器反馈的环境信息调整策略这比传统的固定脚本自动化要灵活和健壮得多。3. 环境搭建与核心代码实现3.1 基础环境配置首先我们需要一个干净的 Python 环境建议 3.9 以上。使用虚拟环境是个好习惯。# 创建并激活虚拟环境 python -m venv venv source venv/bin/activate # Linux/Mac # venv\Scripts\activate # Windows # 安装核心依赖 pip install google-generativeai playwright安装 Playwright 后还需要安装它所需的浏览器内核。这一步只需做一次playwright install chromium这里选择安装 Chromium 就足够了因为它最轻量且与 CDP 兼容性最好。接下来去 Google AI Studio 创建一个 API 密钥并妥善保存。3.2 智能代理核心类封装我将核心功能封装在一个SmartBrowserAgent类中这样逻辑更清晰也便于扩展。import asyncio import json import google.generativeai as genai from playwright.async_api import async_playwright, Page, TimeoutError as PlaywrightTimeoutError class SmartBrowserAgent: def __init__(self, api_key: str, model_name: str gemini-1.5-pro): 初始化智能代理 :param api_key: Gemini API 密钥 :param model_name: 使用的模型名称默认为 gemini-1.5-pro genai.configure(api_keyapi_key) self.model genai.GenerativeModel( model_name, generation_config{ temperature: 0.1, # 低随机性确保生成的操作代码稳定可靠 response_mime_type: application/json, # 强制返回 JSON 格式 } ) self.playwright None self.browser None self.page: Page None self.context # 用于存储多轮对话的上下文 async def start_browser(self, headless: bool False): 启动浏览器实例。调试阶段建议 headlessFalse 以便观察。 self.playwright await async_playwright().start() self.browser await self.playwright.chromium.launch(headlessheadless) self.page await self.browser.new_page() # 设置默认超时和视口大小 await self.page.set_viewport_size({width: 1280, height: 720}) self.page.set_default_timeout(30000) # 30秒 async def get_page_context(self) - str: 获取当前页面的结构化上下文信息这是给模型看的‘眼睛’ if not self.page: return Browser not started. # 获取核心页面信息 url self.page.url title await self.page.title() # 获取所有可能有交互性的元素信息这是一个简化示例实际可以更精细 # 这里我们获取所有 button, a, input, select 元素的简要信息 elements_info await self.page.evaluate( () { const items []; const selectors button, a[href], input:not([typehidden]), select, textarea, [rolebutton], [rolelink]; document.querySelectorAll(selectors).forEach(el { const rect el.getBoundingClientRect(); if (rect.width 0 rect.height 0) { // 粗略判断可见 items.push({ tag: el.tagName.toLowerCase(), text: (el.textContent || el.value || el.placeholder || ).slice(0, 50).trim(), id: el.id, classes: Array.from(el.classList).join(.), type: el.type, name: el.name, selector: #${el.id} || .${Array.from(el.classList).join(.)} || el.tagName.toLowerCase() }); } }); return JSON.stringify(items); } ) context f 当前页面状态 - 网址{url} - 标题{title} - 可交互元素部分 {elements_info} 请根据以上页面状态执行用户指令。你的响应必须是严格的 JSON 格式包含 action 和 code 字段。 action 字段描述你要做什么如navigate, click, fill, extract, done。 code 字段是可直接在 Playwright Page 对象上执行的 JavaScript 代码字符串。 return context async def execute_instruction(self, user_instruction: str): 核心方法执行一条自然语言指令 print(f\n[用户指令] {user_instruction}) # 将指令和当前页面上下文组合成提示词 page_context await self.get_page_context() prompt f {page_context} 用户指令{user_instruction} 请分析当前页面和用户指令决定下一步操作。如果任务已完成action 设为 done。 # 调用 Gemini 模型 try: response await self.model.generate_content_async(prompt) # 解析模型返回的 JSON response_text response.text.strip(json\n).strip(\n).strip() decision json.loads(response_text) action decision.get(action) code decision.get(code) print(f[模型决策] Action: {action}, Code: {code}) if action done: print(任务完成。) return True if code: # 在 Playwright 页面上下文中执行生成的代码 result await self.page.evaluate(code) print(f[执行结果] {result}) # 执行后稍作等待让页面状态稳定 await self.page.wait_for_timeout(1000) # 递归执行直到任务完成或达到最大步数此处省略循环控制逻辑 # 实际应用中这里应有一个循环或状态机来管理多步任务 return False except json.JSONDecodeError as e: print(f模型返回非 JSON 格式: {response.text}) return True except PlaywrightTimeoutError as e: print(f执行超时: {e}) # 可以将超时错误反馈给模型让其重试或调整策略 return False except Exception as e: print(f执行过程中发生错误: {e}) return True async def close(self): 清理资源 if self.browser: await self.browser.close() if self.playwright: await self.playwright.stop()这个类封装了核心流程启动浏览器、获取页面上下文、调用 Gemini 决策、执行操作。get_page_context函数是关键它决定了模型能“看到”多少页面信息。上面的实现是一个基础版本实际应用中可能需要提取更丰富的信息如表单结构、数据列表、特定区域截图等。3.3 一个完整的任务执行示例假设我们要让代理完成“打开 GitHub 趋势页面并获取前三个仓库的名字”这个任务。我们不会直接写死操作而是通过自然语言驱动。import asyncio from smart_browser_agent import SmartBrowserAgent # 假设上面的类保存在这个文件 async def main(): agent SmartBrowserAgent(api_keyYOUR_GEMINI_API_KEY) try: # 1. 启动浏览器非无头模式方便观察 await agent.start_browser(headlessFalse) # 2. 执行一个多步指令。在实际智能体中这个指令会被模型分解。 # 这里我们模拟一个分步过程。 instructions [ 导航到 GitHub 趋势页面 (https://github.com/trending), 等待页面上的仓库列表加载出来, 提取列表中最前面三个仓库的名字和链接, ] for instr in instructions: done await agent.execute_instruction(instr) if done: break # 可以在这里加入更复杂的循环和状态判断逻辑 # 3. 最后我们可以手动检查一下结果或者让模型输出总结 final_data await agent.page.evaluate( () { const repos []; document.querySelectorAll(article h2 a).forEach((link, index) { if (index 3) { repos.push({ name: link.textContent.trim(), url: link.href }); } }); return repos; } ) print(提取到的仓库信息, final_data) await asyncio.sleep(5) # 暂停一下看看结果 finally: await agent.close() if __name__ __main__: asyncio.run(main())在这个示例中execute_instruction方法会被调用三次。每次调用模型都会根据当时的页面状态和新的指令来决定做什么。第一次页面是空的所以它会生成导航代码。第二次页面正在加载它可能会生成一个等待某个特定选择器出现的代码。第三次页面加载完毕它会生成提取数据的代码。这种“感知-决策-执行”的循环正是智能代理的核心。4. 高级技巧与优化策略4.1 提升模型“视力”更丰富的页面上下文基础的元素选择器信息往往不够。为了处理更复杂的页面我们需要给模型提供更强大的“视力”。屏幕截图视觉模型除了 DOM 信息还可以截取当前屏幕或特定区域的截图使用 Gemini 1.5 Pro 等支持多模态的模型进行视觉分析。这对于识别图标、验证码、或布局极其复杂的组件如 Canvas 绘图非常有效。你可以将截图转换为 base64 编码与文本上下文一起发送给模型。可访问性树通过await page.accessibility.snapshot()获取页面的可访问性树。这棵树描述了页面的语义结构如按钮、标题、区域对于理解页面的功能区域比纯 DOM 更高效。网络请求监控通过 Playwright 监听网络请求 (page.on(‘request’)和page.on(‘response’))。将关键的 API 请求和响应特别是 XHR/Fetch 请求摘要提供给模型。当用户指令是“获取列表数据”时模型可能会发现直接调用底层 API 比操作 DOM 更高效。4.2 设计高效的提示工程模型的性能很大程度上取决于你如何“提问”。针对浏览器代理任务提示词需要精心设计。系统提示词在初始化模型时可以设定一个系统角色。self.model genai.GenerativeModel( model_name, system_instruction你是一个专业的网页自动化助手。你的任务是将用户的自然语言指令转化为对网页的安全、精确操作。 你必须始终以 JSON 格式响应包含 action 和 code 字段。 action 必须是以下之一navigate, click, fill, select, scroll, extract, wait, done。 code 必须是单行或可在 Playwright Page 上下文中安全执行的 JavaScript 代码片段。 优先使用稳定且唯一的 CSS 选择器如ID、具有特定意义的类。避免使用可能变化的索引位置。 如果指令不明确或无法在当前页面执行请询问澄清问题action 设为 clarify。 )上下文管理维持一个对话历史列表将之前的交互用户指令、模型决策、执行结果作为上下文传递给下一次调用。这能让模型记住任务目标做出连贯的决策。但要注意上下文长度限制必要时进行摘要。结构化输出强制要求 JSON 输出 (response_mime_type“application/json”) 是保证后续代码能稳定解析的关键。可以定义更复杂的输出模式比如包含备用选择器、预期结果描述等字段。4.3 实现健壮的错误处理与重试机制网络环境、页面动态变化、模型“幻觉”都会导致操作失败。一个工业级的代理必须有完善的错误处理。操作失败检测Playwright 操作如click,fill会抛出异常。捕获这些异常并将错误信息如Error: Element not found for selector: .btn-submit反馈给模型。提示模型分析错误原因并生成新的策略例如“选择器.btn-submit未找到。当前页面有一个button[type‘submit’]和一个#loginBtn。请根据页面上下文选择一个更可能正确的选择器重试。”超时与等待策略不要依赖固定的sleep。使用 Playwright 的wait_for_selector,wait_for_function,wait_for_load_state等方法并设置合理的超时时间。模型生成的代码应包含这些等待逻辑。循环与终止条件对于一个多步任务需要设置最大步数限制防止进入死循环。同时定义清晰的任务完成状态例如成功跳转到某个 URL、成功获取到目标数据让模型能准确判断何时返回action: “done”。5. 实战应用场景与避坑指南5.1 典型应用场景剖析复杂数据抓取与整理传统爬虫难以处理需要登录、交互点击“加载更多”、下拉筛选的网站。智能代理可以理解“登录后点开第二个选项卡筛选2023年的数据然后导出CSV”这样的指令模拟真人操作完成数据获取。难点在于对抗网站的反爬机制如指纹识别需要配合 Playwright 的上下文伪装、代理轮换等高级功能。自动化测试与监控不仅仅是回归测试。你可以告诉代理“每天上午9点检查官网的订单提交流程是否畅通从商品页加入购物车到支付成功并截图最后一步。”它能生成测试脚本并执行发现页面改版导致的元素选择器失效时还能尝试自我修复通过更新的页面上下文寻找新选择器。个人工作流自动化处理那些没有开放 API 的网页工具。例如“每周一早上从内部报表网站下载上周的销售数据表重命名为‘销售_YYYYMMDD.xlsx’并发送邮件给团队。”这需要结合文件操作、邮件发送等本地能力代理可以生成 Python 主脚本调用 Playwright 完成网页部分。研究与竞品分析快速遍历竞品网站的功能点。“遍历这个 SaaS 产品的定价页面、文档页面和博客总结出它们强调的五个核心功能特性。”代理可以自动导航、滚动、点击并将页面关键文本提取出来供进一步分析。5.2 常见问题与排查技巧实录在实际开发中我踩过不少坑这里总结几个最典型的问题1模型生成的 CSS 选择器不稳定经常失效。现象今天还能用的.btn-primary明天页面改版就找不到了。根因模型倾向于使用它“看到”的文本和类名但这些往往是前端框架动态生成或可变的。解决方案提示词引导在系统提示中强调“优先使用id、name、>

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价