实战:使用 Stagehand + Qwen (通义千问) 实现智能化浏览器自动化

什么是 Stagehand?

Stagehand 是一个专为 AI 时代设计的浏览器自动化 SDK。它建立在强大的 Playwright 之上,但彻底改变了我们与浏览器交互的方式。

传统的自动化工具(如 Selenium 或原生 Playwright)要求开发者像“工匠”一样,精确地指定每一个操作的坐标或元素选择器(如 div > .btn-primary)。一旦网页结构微调,脚本往往就会失效。

Stagehand 则让开发者变成了“指挥官”。 你不再需要关心底层的 DOM 结构,只需用自然语言下达指令(例如“点击注册按钮”或“提取所有商品价格”),Stagehand 就会利用大语言模型(LLM)的视觉和语义理解能力,自动分析页面并执行操作。它主要提供了三个核心能力:

  • Act (行动): 执行具体操作(如点击、输入、滚动)。
  • Extract (提取): 从页面中智能提取结构化数据。
  • Observe (观察): 分析页面当前状态,为后续决策提供依据。

在浏览器自动化领域,Playwright 和 Selenium 是我们熟悉的工具,但它们通常需要精确的选择器(Selectors)和硬编码的逻辑。如果能让脚本“看懂”页面并根据自然语言指令行动呢?

本文将基于一段实战代码 test_stagehand_qwen.py,深入解析如何利用 Stagehand 框架结合阿里云 Qwen (通义千问) 大模型,构建一个能够理解自然语言指令的自动化脚本。

1. 快速开始

1.1 安装依赖

在使用本技术之前,你需要安装 Stagehand 的 Python SDK 以及 Playwright 和环境变量管理工具。

打开终端,运行以下命令:

# 安装核心依赖
pip install stagehand playwright python-dotenv

# 安装 Playwright 浏览器驱动
playwright install

1.2 准备工作

  1. 获取 API Key: 确保你拥有阿里云 DashScope 的 API Key(用于调用 Qwen 模型)。
  2. 配置环境: 在项目根目录创建 .env 文件,填入你的 API Key:
    DASHSCOPE_API_KEY=sk-xxxxxxxxxxxxxxxxxxxxxxxx
    

2. 核心技术栈

  • Stagehand: 一个旨在让 AI 驱动浏览器自动化的 SDK,它在 Playwright 之上提供了更高级的抽象(act, extract, observe)。
  • Qwen (通义千问): 阿里云强大的大语言模型,这里我们使用的是 qwen3-max-preview,通过 DashScope API 调用。
  • Python Asyncio: 用于处理异步浏览器操作。

3. 代码深度解析

3.1 环境配置与模型集成

传统的自动化脚本通常难以适配不同的 LLM,但 Stagehand 提供了灵活的配置接口。代码首先配置了 DashScope(灵积模型服务)作为 AI 后端。

import os
from stagehand import Stagehand, StagehandConfig
from dotenv import load_dotenv

# 加载环境变量
load_dotenv()

async def main():
    # 设置 DashScope API Base 地址
    os.environ['DASHSCOPE_API_BASE'] = "https://dashscope.aliyuncs.com/compatible-mode/v1"

    config = StagehandConfig(
        env="LOCAL",
        # 指定使用 Qwen 模型
        modelName="dashscope/qwen3-max-preview",
        modelApiKey=os.getenv("DASHSCOPE_API_KEY"),
        # ... 其他配置
    )

关键点:

  • 自定义模型:通过 modelName="dashscope/qwen3-max-preview",我们指示 Stagehand 使用兼容 OpenAI 协议的 Qwen 模型。
  • API Base:设置 DASHSCOPE_API_BASE 指向阿里云的兼容接口,这是集成非 OpenAI 官方模型的关键技巧。

3.2 浏览器与调试参数调优

为了保证自动化过程的稳定性和可观测性,配置中包含了大量细节调优:

    config = StagehandConfig(
        # ... 基础配置
        headless=True,               # 无头模式运行
        verbose=3,                   # 详细日志级别
        debug_dom=True,              # 启用 DOM 调试,帮助 AI 理解页面结构
        dom_settle_timeout_ms=60000, # 增加 DOM 稳定超时时间,应对动态加载页面
        wait_for_network_idle_ms=5000, # 等待网络空闲
        local_browser_launch_options={
            "slow_mo": 100,          # 慢动作模式,便于人眼观察每一步操作
            "devtools": True,        # 开启开发者工具
            "args": [
                "--window-size=1920,1080",
                "--disable-web-security",  # 解决跨域等安全限制问题
            ]
        }
    )

这些参数对于调试 AI 驱动的自动化非常重要,特别是 dom_settle_timeout_msdebug_dom,它们能显著提高 AI 在复杂单页应用(SPA)中的识别准确率。

3.3 自然语言驱动的操作 (Act)

Stagehand 的核心魔力在于 act 方法。我们不再查找 XPath 或 CSS Selector,而是直接告诉它“要做什么”。

    stagehand = Stagehand(config)
    await stagehand.init()
    page = stagehand.page

    # 1. 访问目标网站(示例中使用百度)
    await page.goto("https://www.baidu.com/")

    # 2. 自然语言指令:输入搜索词
    await page.act("在搜索框中输入搜索词'天气'")

    # 3. 自然语言指令:点击搜索
    await page.act("点击搜索按钮")

AI 是如何工作的?
Stagehand 会抓取当前页面的 DOM 快照,将其简化后发送给 Qwen 模型。Qwen 理解“搜索框”和“输入”的语义,返回具体的 Playwright 操作指令。这使得脚本对页面改版具有极强的鲁棒性——只要搜索框还在,脚本就能跑。

3.4 智能信息提取 (Extract)

除了操作,Stagehand 还支持结构化数据提取。

    # 提取页面主要内容
    content = await page.extract("提取页面中与天气相关的主要信息", schema=None)
    print(f"搜索结果: {content}")

extract 方法不仅仅是抓取文本,它会根据你的指令(Prompt)从杂乱的 HTML 中提炼出关键信息。这对于爬虫开发来说是一个巨大的效率提升。

4. 技术优势

相比于传统的浏览器自动化方案,结合 Stagehand 和 Qwen 的方案具有以下显著优势:

  1. 零选择器维护 (Zero-Selector Maintenance)

    • 传统痛点: 页面改版导致 class 或 id 变化,脚本即刻失效。
    • 本方案优势: 基于视觉和语义理解页面,只要元素还在(哪怕位置变了、样式变了),脚本依然能找到并操作。
  2. 自然语言驱动 (Natural Language Driven)

    • 传统痛点: 需要编写复杂的 page.click('div > span:nth-child(2)') 代码,可读性差。
    • 本方案优势: 直接使用 page.act("点击搜索按钮"),代码即文档,非技术人员也能看懂。
  3. 自适应与容错 (Adaptive & Robust)

    • 传统痛点: 遇到意外弹窗或加载延迟,脚本容易报错退出。
    • 本方案优势: 大模型具备一定的推理能力,可以根据上下文判断当前状态,甚至处理意料之外的简单交互。
  4. 智能提取 (Intelligent Extraction)

    • 传统痛点: 编写正则表达式或解析规则提取数据非常繁琐且容易出错。
    • 本方案优势: extract 方法能直接将非结构化 HTML 转化为结构化的 JSON 数据。

5. 场景对比与应用

场景 传统方案 (Selenium/Playwright) 智能化方案 (Stagehand + Qwen) 智能化方案优势
端到端测试 (E2E) 脚本脆弱,UI 微调需频繁维护脚本。 关注业务逻辑而非 UI 实现细节。 维护成本降低 80%,测试脚本更稳定,不因前端改版而频繁重写。
通用爬虫/数据采集 针对每个网站编写特定的解析规则,反爬对抗成本高。 通用指令提取数据(如“提取所有商品价格”)。 开发效率极高,一套逻辑可适配多个结构相似的网站;自动适应页面结构变化。
RPA (流程自动化) 仅能处理固定流程,遇到异常弹窗或分支流程容易卡死。 具备“视觉”和“大脑”,能动态决策下一步操作。 更强的鲁棒性,能处理复杂的动态流程和非预期异常。
竞品监控 需要长期维护针对竞品网站的抓取脚本。 即使竞品网站改版,监控脚本依然有效。 长期稳定性好,减少因目标网站更新导致的数据中断。

6. 总结

这段代码展示了下一代浏览器自动化的雏形:

  1. 去选择器化:不再依赖脆弱的 CSS/XPath 选择器。
  2. 语义理解:模型理解“输入”、“点击”、“提取”的意图。
  3. 多模型支持:证明了国产大模型(如 Qwen)完全有能力胜任此类复杂的 Agent 任务。

通过 test_stagehand_qwen.py,我们看到了一个高度可配置、易于调试且具备 AI 智能的自动化测试/爬虫方案。无论是用于端到端测试(E2E Testing)还是数据采集,这种模式都极具潜力。

7. 完整示例代码

import asyncio
import os
from stagehand import Stagehand, StagehandConfig
from dotenv import load_dotenv

# 加载环境变量
load_dotenv()

async def main():
    print("Testing Stagehand with Local Playwright...")
    os.environ['DASHSCOPE_API_BASE'] = "https://dashscope.aliyuncs.com/compatible-mode/v1"

    # 尝试配置使用 Qwen
    # 注意:这里假设 litellm 支持 'qwen-max' 并且 Stagehand 允许自定义模型字符串
    config = StagehandConfig(
        env="LOCAL",
        modelName="dashscope/qwen3-max-preview",
        modelApiKey=os.getenv("DASHSCOPE_API_KEY"),
        headless=True,
        verbose=3,
        debug_dom=True,              # 启用DOM调试
        dom_settle_timeout_ms=60000, # 增加DOM稳定超时时间
        wait_for_network_idle_ms=5000, # 等待网络空闲的时间
        local_browser_launch_options={  # 本地浏览器启动选项
            "slow_mo": 100,          # 减慢操作速度以便观察
            "devtools": True,        # 打开开发者工具
            "args": [
                "--window-size=1920,1080",  # 设置窗口大小
                "--disable-web-security",   # 禁用网络安全限制
                "--disable-features=IsolateOrigins,site-per-process"  # 禁用某些隔离功能
            ]
        }
    )
    
    stagehand = Stagehand(config)

    try:
        await stagehand.init()
        
        page = stagehand.page
        print("=== 百度搜索测试任务 ===")

        # 1. 访问必应
        print("1. 正在访问百度...")
        await page.goto("https://www.baidu.com/")
        print("   已访问百度")

        # 等待页面加载完成
        await asyncio.sleep(3)

        # 2. 输入搜索词
        print("2. 正在输入搜索词...")
        await page.act("在搜索框中输入搜索词'天气'")
        print("   已输入搜索词")

        # 等待输入完成
        await asyncio.sleep(2)

        # 3. 点击搜索
        print("3. 正在点击搜索按钮...")
        await page.act("点击搜索按钮")
        print("   已点击搜索按钮")

        # 等待搜索结果页面加载
        await asyncio.sleep(5)

        # 验证操作结果
        print("4. 正在验证搜索结果...")
        title = await page.title()
        print(f"   当前页面标题: {title}")

        # 获取页面URL验证是否跳转
        current_url = page.url
        print(f"   当前页面URL: {current_url}")

        # 提取页面主要内容
        print("5. 正在提取搜索结果...")
        content = await page.extract("提取页面中与天气相关的主要信息", schema=None)
        print(f"   搜索结果: {content}")

        # 保持浏览器打开一段时间以便观察
        print("6. 保持浏览器打开10秒钟以便观察...")
        await asyncio.sleep(10)

        print("=== 百度搜索测试完成 ===")
        
    except Exception as e:
        print(f"Error: {e}")
        import traceback
        traceback.print_exc()
    finally:
        await stagehand.close()

if __name__ == "__main__":
    asyncio.run(main())

posted on 2025-12-23 08:35  天涯轩  阅读(1)  评论(0)    收藏  举报

导航