xiaohack's Blog - Puppeteer
type: channel
link: https://blog.xiaohack.org/tag/puppeteer/
items: 快速上手：LangChain + AgentRun 浏览器沙箱极简集成指南
items: 为什么不一定需要 debugger 做浏览器控制?
items: 【Gemini business】自动注册机及自动刷新，成功率 99%，可并发

快速上手：LangChain + AgentRun 浏览器沙箱极简集成指南
type: item
date: 2026-01-22T17:35:21+08:00
description: 作者：辰泉前言在 Agentic AI 时代，智能体需要与真实世界交互，而浏览器是连接虚拟世界与现实世界的重要桥梁。AgentRun Browser Sandbox 为智能体提供了安全、高性能、免运维的浏览器执行环境，让 AI Agent 真正具备“上网”的能力——从网页抓取、信息提取到表单填写、自动化操作，一切皆可实现。AgentRun Browser Sandbox 介绍什么是 Browser Sandbox?Browser Sandbox 是 AgentRun 平台提供的云原生无头浏览器沙箱服务，基于阿里云函数计算（FC）构建。它为智能体提供了一个安全隔离的浏览器执行环境，支持通过标准的 Chrome DevTools Protocol (CDP) 远程控制浏览器实例。核心特性无头浏览器能力内置 Chromium/Chrome 浏览器，支持完整的 Web 标准原生兼容 Puppeteer、Playwright 等主流自动化框架支持通过 CDP 协议进行精细化控制实时可视化内置 VNC 服务，支持实时查看浏览器界面提供操作录制功能，方便调试和回放支持通过 noVNC 客户端在网页中直接交互安全与隔离每个沙箱实例运行在独立的容器环境中文件系统和进程空间完全隔离支持 WSS 加密传输，确保数据安全Serverless 架构按需创建，按量付费，无需提前预置资源快速弹性伸缩，支持高并发场景零运维，无需管理服务器和浏览器依赖主要应用场景AI Agent 赋能： 为大模型提供“眼睛”和“手”，执行网页浏览、信息提取、在线操作等任务自动化测试： 在云端运行端到端（E2E）测试和视觉回归测试数据采集： 稳定、高效地进行网页抓取，应对动态加载和反爬虫挑战内容生成： 自动化生成网页截图或 PDF 文档上手使用 AgentRun Browser SandboxAgentRun SDK 快速介绍后续的内容将基于 AgentRun SDK 进行，因此我们先对 SDK 进行简要介绍。Agentrun SDK 是一个开源的开发者工具包，本期介绍 Python 版本。其旨在简化智能体与 AgentRun 平台各种服务（包括 Browser Sandbox）的集成。它提供了统一的接口，让您可以用几行代码就将沙箱能力集成到现有的 Agent 框架中。SDK 的核心功能如下：统一集成接口提供对 LangChain、AgentScope 等主流框架的开箱即用支持统一的模型代理接口，简化多模型管理标准化的工具注册机制Sandbox 生命周期管理自动创建和销毁沙箱实例支持会话级别的状态保持灵活的资源配置和超时控制安装 AgentRun SDKpip install agentrun-sdk[playwright,server]注意： 确保您的 Python 环境版本在 3.10 及以上。基本使用示例以下是使用 AgentRun SDK 创建和管理 Browser Sandbox 的核心代码：from agentrun.sandbox import Sandbox, TemplateType from playwright.sync_api import sync_playwright # 创建 Browser Sandbox sandbox = Sandbox.create( template_type=TemplateType.BROWSER, template_name="your-template-name", sandbox_idle_timeout_seconds=300 ) # 获取 CDP URL（用于 Playwright 连接） cdp_url = sandbox.get_cdp_url() # 使用 Playwright 连接并操作 with sync_playwright() as p: browser = p.chromium.connect_over_cdp(cdp_url) page = browser.contexts[0].pages[0] page.goto("https://www.example.com") page.screenshot(path="screenshot.png") browser.close() # 销毁 Sandbox sandbox.delete()关键概念：template_name： 控制台创建的浏览器环境模板cdp_url： 用于 Playwright/Puppeteer 连接vnc_url： 用于实时查看浏览器画面（可通过 sandbox.get_cdp_url() 获取）注意： 由于所有浏览器操作都在云端进行，您无需在本地安装浏览器。Playwright 仅用于通过 CDP 协议连接到云端的浏览…

为什么不一定需要 debugger 做浏览器控制?
type: item
date: 2026-01-14T09:21:38+08:00
description: AIPex 最新发布了新版本，其中最重要的能力之一，是浏览器任务可以在后台运行，而不打断用户的正常工作流。这一能力并非来自某个“技巧”，而是源于一个明确的工程选择： 我们有意识地避免将浏览器控制建立在 debugger （ Chrome DevTools Protocol ）之上。本文将解释为什么主流方案普遍选择 debugger ，以及 AIPex 为什么在多数智能代理与日常自动化场景中，选择了一条不同的路线。为什么大多数浏览器控制方案选择 debugger （ CDP ）在当前无需迁移的浏览器自动化插件或 Agent 中，常见方案包括： Manus 的 Manus Browser Operator Claude 推出的 Claude in Chrome 开源社区的 nano browser 以及 Puppeteer / Playwright 等自动化工具的扩展形态 这些方案通常基于 Chrome DevTools Protocol （ CDP ），尤其是其 debugger 能力来实现浏览器控制，原因并不复杂：1. 能力覆盖完整CDP 提供了浏览器内部几乎所有关键能力，包括： 页面导航与生命周期控制 DOM 与 AXTree （ Accessibility Tree ）访问 事件注入（鼠标、键盘、滚轮） 网络拦截与修改 截图、录屏、性能采样 对于复杂自动化而言，CDP 是一个“开箱即用”的全能力接口。2. 可访问性树（ AXTree ）高度语义化通过 CDP ，可以直接获取浏览器构建的 Accessibility Tree： 每个节点都具备 role / name / state 天然适合语音辅助与 AI 理解 在理想 ARIA 实现下，语义质量很高 因此，AXTree 成为了许多 AI Agent 的主要页面表达形式。3. 工程生态成熟围绕 CDP 已经形成成熟工具链： Puppeteer 、Playwright 等底层实现 完整的文档、示例与社区经验 对自动化工程师而言，学习与接入成本明确 debugger （ CDP ）在桌面场景中的现实代价尽管 CDP 能力强大，但在“与用户并行工作的桌面场景”中，它也带来了一些难以忽视的问题。1. 前台焦点与用户体验问题CDP 并非以“后台无打扰”为设计目标。在真实桌面环境中： debugger attach 往往会触发 Tab 激活或窗口前置 输入与视觉焦点可能被强制抢占 即使通过 headless 或参数规避，也难以在不同平台与浏览器上保证一致行为 结果是： 当用户正在使用其他应用或标签页时，自动化任务可能打断其当前操作，严重影响体验。2. 浏览器与运行环境耦合使用 CDP 通常意味着： 需要启用调试端口 强绑定 Chrome / Chromium 对部分嵌入式 WebView 、受限环境或非 Chromium 浏览器支持不佳 在企业环境或多浏览器生态中，这种耦合会显著增加部署与维护成本。3. 安全与权限摩擦调试端口、进程权限、证书配置等问题，在企业与受管环境中常常触发： 安全策略拦截 合规审查 IT 运维阻力 这类问题并非技术不可解，而是部署摩擦成本过高。为什么浏览器控制不一定需要 debuggerAIPex 的核心设计目标是：让浏览器任务像“背景思考”一样运行，而不是像“远程操控”一样打断用户。为此，我们选择了一条不以 debugger 为中心的路径。AIPex 的方案：DOM 语义快照 + 轻量交互在页面侧，AIPex 采用纯 JavaScript / TypeScript 能力，实现： 语义化页面快照 稳定节点映射 轻量级事件交互 而不是依赖 CDP 的 AXTree 与调试通道。1. 语义快照，而非调试树AIPex 基于 @aipexstudio/dom-snapshot： 直接遍历 DOM Tree 提取可访问性相关语义（ role / name / state ） 不依赖 CDP 的 Accessibility Tree （ AXTree ） 该库在 README 中明确说明： 它是一个纯 DOM 方案，而非 CDP 的替代封装。2. 稳定、可复用的节点 ID自动为页面元素生成稳定的：data-aipex-nodeid这使得： “语义快照中的节点”与“真实 DOM 元素”之间的映射可长期复用 避免调试态下常见的选择器漂移问题 支持从文本命中直接反查到可操作元素 3. 面向可交互对象的快照策略语义快照优先关注： 按钮、链接、输入框等可操作元素 对话与任务相关的界面子集 并过滤： display: none visibility: hidden aria-hidden inert 从而避免将无意义或不可见节点暴露给 Agent 。4. 文本化表达与语义搜索快照可被转…

【Gemini business】自动注册机及自动刷新，成功率 99%，可并发
type: item
date: 2026-01-03T12:07:28+08:00
description: Gemini bussiness 自动刷新逻辑，接入 yescapture 打码服务，做到了基本 100% 的成功率【回顾】 在之前的自动化注册或者刷新中会出现验证码发送错误的情况，原因在于获取的谷歌验证分数太低导致发送接口错误【探索】通过抓包发现，以下接口就是发送邮件的接口https://accountverification.business.gemini.google/_/IdentityPlatformFrontendUI/data/batchexecute?rpcids=IjXaFf&source-path=%2Fv1%2Fverify-oob-code&bl=boq_cloud-identity-identityplatform-frontend_20251210.10_p1&hl=en&rt=c 请求体为 f.req:["IjXaFf",,null,"generic"] 里面的 0cAFcWe 就是开头的验证因此，只需要接入打码服务即可完成再次发送，测试结果为成功率基本 100%完整 nodejs 代码如下： const fs = require('fs'); const os = require('os'); const path = require('path'); const axios = require('axios'); const express = require('express'); const puppeteer = require('puppeteer-extra'); const StealthPlugin = require('puppeteer-extra-plugin-stealth'); const { ImapFlow } = require('imapflow'); const { simpleParser } = require('mailparser'); puppeteer.use(StealthPlugin()); const app = express(); const port = 3000; // =============================== // 配置项 // =============================== const WEBSITE_KEY = '6Ld8dCcrAAAAAFVbDMVZy8aNRwCjakBVaDEdRUH8'; const WEBSITE_URL = 'https://accountverification.business.gemini.google'; const sleep = (ms) => new Promise(r => setTimeout(r, ms)); function createTempUserDataDir() { return fs.mkdtempSync(path.join(os.tmpdir(), 'pptr-profile-')); } /** * 邮件获取类 */ class GeminiFetcher { constructor(email, clientId, refreshToken) { this.email = email; this.clientId = clientId; this.refreshToken = refreshToken; } async getAccessToken() { const params = new URLSearchParams({ client_id: this.clientId, grant_type: 'refresh_token', refresh_token: this.refreshToken }); const res = await axios.post('https://login.microsoftonline.com/consumers/oauth2/v2.0/token', params.toString()); return res.data.access_token; } async tryFetchOnce() { const token = await this.getAccessToken(); const client = new ImapFlow({ host: 'outlook.office365.com', port: 993, secure: true, auth: { user: this.email, accessToken: token }, logger: false }); await client.connect(); let code = null; try …