• 简体中文
  • Web / Puppeteer SDK

    @midscene/web/puppeteer 提供绑定 Puppeteer 页面或 Browser 的 Agent。两种 Agent 都继承基础 Agent 的 AI 方法,并支持 Web 配置选项。

    导入与 API 概览

    import {
      PuppeteerPageAgent,
      PuppeteerAgent,
      PuppeteerBrowserAgent,
    } from '@midscene/web/puppeteer';
    API作用范围用途
    PuppeteerPageAgent单个 Page始终操作同一个页面
    PuppeteerAgent单个 PagePuppeteerPageAgent 的兼容别名,行为相同
    PuppeteerBrowserAgent一个 Browser在浏览器的多个页面之间切换,后续 AI 操作作用于当前 active page

    以下签名中的 Page、Browser 来自 puppeteer;配置类型来自 @midscene/web/puppeteer。

    PuppeteerPageAgent

    new PuppeteerPageAgent(page: Page, options?: PuppeteerPageAgentOpt)
    • page:必填,已有的 Puppeteer 页面。未传入时抛出错误。
    • options:可选,支持通用 Agent 配置和下方的 Web 配置。
    const agent = new PuppeteerPageAgent(page, {
      forceSameTabNavigation: false,
    });
    await agent.aiAct('点击登录按钮');

    Agent 绑定传入的页面。默认 forceSameTabNavigation: true,会拦截 window.open 和 target="_blank" 链接,使其在当前页面打开。设为 false 后保留新标签页行为,但 Agent 不会自动切换到新页面。

    PuppeteerBrowserAgent

    new PuppeteerBrowserAgent(
      browser: Browser,
      initialPage: Page,
      options?: PuppeteerBrowserAgentOpt,
    )
    • browser:必填,用于监听页面创建事件、列出和创建页面的 Browser。
    • initialPage:必填,初始 active page,应使用该 browser 中的页面。
    • options:可选,支持通用 Agent 配置、Web 配置和下面的专属选项。

    未传入 browser 或 initialPage 时抛出错误。Browser Agent 不接受 forceSameTabNavigation;即使通过 JavaScript 传入 false 也会报错。

    PuppeteerBrowserAgent.create()

    PuppeteerBrowserAgent.create(
      browser: Browser,
      options?: PuppeteerBrowserAgentCreateOpt,
    ): Promise<PuppeteerBrowserAgent>

    异步创建 Agent。初始页面按以下顺序选择:options.initialPage → (await browser.pages())[0] → await browser.newPage()。

    const agent = await PuppeteerBrowserAgent.create(browser, {
      autoFollowNewPage: true,
    });

    专属配置

    参数类型默认值说明
    autoFollowNewPagebooleanfalsebrowser 创建新页面时自动将其设为 active page
    newPageTimeoutnumber5000waitForNewPage() 默认等待时间,单位毫秒
    initialPagePage自动选择仅用于 create(),指定初始 active page

    页面管理 API

    以下属性和方法仅属于 PuppeteerBrowserAgent。

    activePage

    agent.activePage: Page

    只读属性,返回当前 AI 操作使用的 Puppeteer 页面。使用 setActivePage() 切换。

    pages()

    agent.pages(): Promise<Page[]>

    返回绑定 browser 中的页面,不改变 active page。

    newPage()

    agent.newPage(): Promise<Page>

    在绑定浏览器的默认 BrowserContext 中创建页面,将其设为 active page,并返回该页面。

    setActivePage()

    agent.setActivePage(page: Page): Promise<void>

    将指定页面设为 active page,并尝试将其置于前台。传入无效或已关闭的页面时抛出错误。应传入绑定 browser 中的页面。

    waitForNewPage()

    agent.waitForNewPage(
      action?: () => Promise<unknown> | unknown,
      options?: { timeout?: number },
    ): Promise<Page>

    先监听 browser 的 targetcreated 事件(仅处理页面类型的 target),再执行可选的 action,返回监听到的新页面。options.timeout 覆盖本次等待时间,单位毫秒;默认使用 newPageTimeout。超时或 action 失败时抛出错误。

    此方法本身不会切换 active page。若设置了 autoFollowNewPage: true,独立的新页面监听器仍会自动切换。需要显式控制切换时,保持该选项为 false:

    const agent = await PuppeteerBrowserAgent.create(browser, {
      autoFollowNewPage: false,
    });
    const newPage = await agent.waitForNewPage(
      () => agent.aiTap('打开详情'),
      { timeout: 10000 },
    );
    await agent.setActivePage(newPage);
    await agent.aiAssert('详情页面已打开');

    配置选项

    除下表外,两种 Agent 均接受通用 Agent 配置,例如模型、报告和缓存配置。

    参数类型默认值说明
    forceSameTabNavigationbooleantrue仅 Page Agent 可用,强制在当前页面打开新标签页链接
    waitForNavigationTimeoutnumber5000等待页面 html 元素的超时,单位毫秒;0 跳过检查。超时后继续执行,不保证应用就绪
    waitForNetworkIdleTimeoutnumber2000动作后等待网络空闲的超时,单位毫秒;要求连续 200 毫秒最多有两个进行中的请求。0 跳过检查,超时后继续执行
    enableTouchEventsInActionSpacebooleanfalse向动作空间添加触摸手势
    keyboardTypeDelaynumber未设置字符输入间隔,单位毫秒,必须是有限非负数;legacy 模式下由 Puppeteer 的 page.keyboard.type 处理正数延迟,未设置时使用底层驱动默认值
    inputStrategy'legacy' | 'sequential' | 'bulk''legacy'文本输入策略;sequential 逐个 Unicode 码点输入,bulk 一次插入完整文本
    forceChromeSelectRenderingbooleantrue注入 base-select 样式,使原生 select 的选项可被截图捕捉;要求 Puppeteer ≥ 24.6.0,且浏览器支持该样式
    customActionsDeviceAction[]未设置向规划器添加自定义动作
    beforeInvokeAction(actionName: string, param: any) => Promise<void>未设置动作执行前的回调
    afterInvokeAction(actionName: string, param: any) => Promise<void>未设置动作执行后的回调
    testRunnerPuppeteerPageAgentOpt['testRunner']未设置为 Midscene Test 的 Puppeteer Nodes 提供 base URL 和 Cookie 等配置

    inputStrategy: 'bulk' 要求不设置 keyboardTypeDelay 或将其设为 0。需要延迟输入时使用 'sequential'。等待业务界面就绪时,使用 aiWaitFor() 或 Puppeteer 自身的等待 API。

    生命周期

    agent.destroy(): Promise<void>

    两种 Agent 都支持 destroy():等待相关操作完成,清理 Agent 持有的资源、调用内部 Device 的 destroy(),并完成报告处理。Browser Agent 还会移除用于自动跟随新页面的 targetcreated 监听器。

    Puppeteer Device 的 destroy() 不关闭传入的 Page、BrowserContext 或 Browser,也不主动断开远程浏览器连接。由调用方管理这些 Puppeteer 资源;销毁 Agent 后,页面和浏览器仍可继续使用。

    try {
      await agent.aiAct('提交表单');
    } finally {
      await agent.destroy();
      // 按资源所有权,由调用方关闭 page、context 或 browser。
    }

    浏览器支持与限制

    推荐使用 Chrome / Chromium。Midscene 的 Puppeteer 集成依赖 CDP,包括触摸手势和部分交互操作。不要将 Puppeteer 自身支持的其他浏览器或协议视为 Midscene 的支持范围。

    远程浏览器

    Agent 接受已有的 Puppeteer 页面,创建方式与本地浏览器一致。例如使用 CDP 连接后:

    import puppeteer from 'puppeteer';
    import { PuppeteerPageAgent } from '@midscene/web/puppeteer';
    
    const browser = await puppeteer.connect({ browserWSEndpoint: cdpWsUrl });
    const page = (await browser.pages())[0] ?? await browser.newPage();
    const agent = new PuppeteerPageAgent(page);

    连接和身份验证由调用方管理。远程浏览器使用完毕后,可调用 browser.disconnect() 断开 Puppeteer 连接并保留浏览器进程;browser.close() 会关闭浏览器。

    获取 CDP WebSocket URL

    你可以从多种来源获取 CDP WebSocket URL:

    • BrowserBase:在 https://browserbase.com 注册并获取你的 CDP URL
    • Browserless:使用 https://browserless.io 或运行你自己的实例
    • 本地 Chrome:使用 --remote-debugging-port=9222 参数运行 Chrome,然后使用 ws://localhost:9222/devtools/browser/...
    • Docker:在 Docker 容器中运行 Chrome 并暴露调试端口

    FAQ

    安装 Puppeteer 很慢,或安装时卡住

    Puppeteer 会在安装时通过 postinstall 自动下载浏览器镜像。下载慢或网络不通时,安装过程就会卡住。

    # 先跳过浏览器下载,让依赖安装完成
    PUPPETEER_SKIP_DOWNLOAD=true pnpm install
    
    # 再单独从镜像站下载 Chrome
    # 下面以 https://registry.npmmirror.com 为例,不同镜像平台的 base-url 规则可能不同
    pnpm exec puppeteer browsers install chrome --base-url="https://registry.npmmirror.com/-/binary/chrome-for-testing"

    下拉框点击不到

    如果点击下拉框后,报告中的截图没有出现下拉选项,通常是页面使用了原生 select 标签,导致展开后的下拉面板由操作系统原生控件渲染,没有真正出现在浏览器页面里。

    Midscene 默认开启 forceChromeSelectRendering 选项,强制由 Chrome 来渲染下拉框;如需关闭可将其设为 false。详细原因、判断方式和效果说明,请参考 Playwright FAQ — 下拉框点击不到。

    浏览器界面持续闪动

    通常是 viewport 的 deviceScaleFactor 与系统像素比不匹配所致。将 deviceScaleFactor 设为 0 可自动适配:

    await page.setViewport({
      width: 1280,
      height: 720,
      deviceScaleFactor: 0,
    });

    更多详情请参考 Playwright FAQ — 浏览器界面持续闪动。

    自定义网络超时

    通过 waitForNavigationTimeout 和 waitForNetworkIdleTimeout 调整或关闭内置检查,详见配置选项。