上一篇 下一篇 分享链接 返回 返回顶部

我用 Playwright 做了个能读网页、总结内容的浏览器助手(附源码)

发布人:慈云数据-客服中心 发布时间:2小时前 阅读量:0

AI浏览器 实战案例分享|附源码

关键词:AI浏览器、智能体、网页自动化、Playwright、LLM、RAG、网页摘要、信息提取、自动化办公

随着大语言模型能力的不断增强,“AI浏览器”正在成为一个非常实用的落地场景。它并不是简单地把 ChatGPT 嵌入浏览器侧边栏,而是让 AI 具备“看网页、理解网页、操作网页、总结信息、完成任务”的能力。

本文将通过一个完整的实战案例,分享如何从零实现一个简易版 AI 浏览器助手:它可以打开指定网页,读取网页内容,提取关键信息,生成摘要,并根据用户指令进行简单的网页自动化操作。文末附上核心源码,方便你直接改造为自己的项目。


一、什么是 AI 浏览器?

传统浏览器主要解决“人访问网页”的问题,而 AI 浏览器试图解决的是:

让 AI 像人一样使用浏览器,并帮助人更高效地完成信息处理与网页操作。

一个典型的 AI 浏览器通常具备以下能力:

  1. 网页理解能力
    能够读取网页中的标题、正文、链接、表格、按钮等信息。

  2. 内容总结能力
    可以对长网页、新闻、博客、论文、产品文档进行摘要。

  3. 信息提取能力
    例如从网页中提取价格、邮箱、公司名称、产品参数、招聘信息等。

  4. 网页操作能力
    能自动点击按钮、填写表单、搜索关键词、翻页等。

  5. 任务规划能力
    用户输入“帮我找出这个页面里最重要的三条信息”,AI 可以规划步骤并执行。

  6. 上下文记忆能力
    可以记住当前网页、用户历史问题、已访问页面内容。

本文的目标不是实现一个完整商业级 AI 浏览器,而是实现一个具备核心能力的 MVP:
打开网页 → 获取内容 → 调用大模型分析 → 返回结果 → 支持简单操作。


二、实战案例说明

我们要实现的案例是:

输入一个网址和一个问题,AI 浏览器自动打开网页,读取页面内容,并回答用户问题。

例如用户输入:

网址:https://example.com/article
问题:请总结这篇文章的核心观点,并列出三个重点。

程序会自动完成以下步骤:

  1. 使用 Playwright 打开网页;
  2. 等待页面加载完成;
  3. 提取网页标题、正文文本、链接等信息;
  4. 将网页内容和用户问题发送给大语言模型;
  5. 生成结构化回答;
  6. 返回给用户。

进一步扩展后,它还可以支持类似指令:

请找到页面中所有下载链接。
请提取页面中的产品价格和规格参数。
请帮我判断这个网页是否包含招聘信息。
请总结这个页面,并生成一段适合发朋友圈的文案。

三、技术选型

本案例采用以下技术栈:

技术 作用
Node.js 后端运行环境
Playwright 控制浏览器,访问和解析网页
OpenAI API / 兼容大模型 API 负责内容理解与生成
Express 提供简单 HTTP API
dotenv 管理环境变量

为什么选择 Playwright?

因为 Playwright 能够真正启动浏览器环境,适合处理现代网页。很多网页内容是通过 JavaScript 动态加载的,普通 HTTP 请求可能拿不到完整内容,而 Playwright 可以像真实用户一样等待页面渲染完成后再获取 DOM 内容。


四、项目目录结构

建议的项目结构如下:

ai-browser-demo
├── package.json
├── .env
├── src
│   ├── index.js
│   ├── browser.js
│   ├── llm.js
│   └── prompt.js
└── README.md

各文件职责如下:

文件 说明
index.js 启动 Express 服务,提供接口
browser.js 使用 Playwright 打开网页并提取内容
llm.js 封装大模型调用
prompt.js 管理提示词模板
.env 存放 API Key 和模型配置

五、安装依赖

首先创建项目:

mkdir ai-browser-demo
cd ai-browser-demo
npm init -y

安装依赖:

npm install express playwright dotenv openai

安装浏览器:

npx playwright install

如果你部署在 Linux 服务器,可能还需要安装系统依赖:

npx playwright install-deps

六、环境变量配置

在项目根目录创建 .env 文件:

PORT=3000

OPENAI_API_KEY=你的_API_KEY
OPENAI_BASE_URL=https://api.openai.com/v1
OPENAI_MODEL=gpt-4o-mini

如果你使用的是兼容 OpenAI 格式的国内或私有模型服务,只需要修改 OPENAI_BASE_URLOPENAI_MODEL 即可。

例如:

OPENAI_BASE_URL=https://your-llm-provider.com/v1
OPENAI_MODEL=your-model-name

七、核心源码

下面是完整核心代码。


1. 浏览器模块:src/browser.js

这个模块负责打开网页并提取页面内容。

const { chromium } = require("playwright");

/**
 * 清洗网页文本,去除多余空白
 */
function cleanText(text) {
  return text
    .replace(/\s+/g, " ")
    .replace(/\n+/g, "\n")
    .trim();
}

/**
 * 截断文本,避免超过模型上下文长度
 */
function truncateText(text, maxLength = 12000) {
  if (!text) return "";
  if (text.length <= maxLength) return text;
  return text.slice(0, maxLength) + "\n\n[内容过长,已截断]";
}

/**
 * 提取网页基础信息
 */
async function extractPageInfo(url) {
  const browser = await chromium.launch({
    headless: true
  });

  const page = await browser.newPage({
    viewport: {
      width: 1280,
      height: 900
    }
  });

  try {
    await page.goto(url, {
      waitUntil: "networkidle",
      timeout: 45000
    });

    const title = await page.title();

    const description = await page
      .locator('meta[name="description"]')
      .getAttribute("content")
      .catch(() => "");

    const bodyText = await page.locator("body").innerText({
      timeout: 10000
    });

    const links = await page.$$eval("a", (anchors) => {
      return anchors
        .map((a) => ({
          text: a.innerText ? a.innerText.trim() : "",
          href: a.href
        }))
        .filter((item) => item.href)
        .slice(0, 80);
    });

    const headings = await page.$$eval("h1,h2,h3", (nodes) => {
      return nodes
        .map((node) => ({
          tag: node.tagName.toLowerCase(),
          text: node.innerText ? node.innerText.trim() : ""
        }))
        .filter((item) => item.text)
        .slice(0, 50);
    });

    return {
      url,
      title,
      description: description || "",
      headings,
      links,
      text: truncateText(cleanText(bodyText))
    };
  } finally {
    await browser.close();
  }
}

module.exports = {
  extractPageInfo
};

这里有几个关键点:

  1. 使用 chromium.launch 启动无头浏览器;
  2. 使用 networkidle 等待页面网络请求基本结束;
  3. 提取 titledescription、正文文本、链接和标题结构;
  4. 对正文进行清洗和截断,避免超过模型上下文长度;
  5. 最后一定要关闭浏览器,避免资源泄露。

2. 提示词模块:src/prompt.js

这个模块负责构造发送给大模型的 Prompt。

function buildWebQuestionPrompt(pageInfo, question) {
  return `
你是一个专业的 AI 浏览器助手,擅长阅读网页、分析网页内容并回答用户问题。

请根据下面提供的网页信息回答用户问题。

要求:
1. 只基于网页内容回答,不要编造不存在的信息;
2. 如果网页内容不足以回答,请明确说明“页面中没有足够信息”;
3. 回答要结构清晰,尽量使用分点说明;
4. 如果用户要求总结,请输出核心观点、关键细节和结论;
5. 如果用户要求提取信息,请使用表格或列表形式。

网页信息如下:

【网址】
${pageInfo.url}

【网页标题】
${pageInfo.title}

【网页描述】
${pageInfo.description || "无"}

【页面标题结构】
${JSON.stringify(pageInfo.headings, null, 2)}

【页面链接】
${JSON.stringify(pageInfo.links, null, 2)}

【网页正文】
${pageInfo.text}

用户问题:
${question}
`;
}

module.exports = {
  buildWebQuestionPrompt
};

Prompt 是 AI 浏览器效果的关键。
如果只把网页正文直接扔给模型,结果可能不稳定;加入标题、描述、链接和结构信息,可以让模型更准确地理解网页。


3. 大模型调用模块:src/llm.js

这里使用 OpenAI SDK,也兼容大多数 OpenAI API 格式的模型服务。

const OpenAI = require("openai");

const client = new OpenAI({
  apiKey: process.env.OPENAI_API_KEY,
  baseURL: process.env.OPENAI_BASE_URL
});

async function askLLM(prompt) {
  const response = await client.chat.completions.create({
    model: process.env.OPENAI_MODEL || "gpt-4o-mini",
    messages: [
      {
        role: "system",
        content:
          "你是一个严谨、可靠的 AI 浏览器助手,擅长分析网页内容。"
      },
      {
        role: "user",
        content: prompt
      }
    ],
    temperature: 0.2
  });

  return response.choices[0].message.content;
}

module.exports = {
  askLLM
};

这里建议将 temperature 设置低一些,例如 0.2,这样模型回答会更稳定,也更适合信息提取和网页分析类任务。


4. 服务入口:src/index.js

这个文件负责启动 HTTP 服务,并提供一个 /ask 接口。

require("dotenv").config();

const express = require("express");
const { extractPageInfo } = require("./browser");
const { buildWebQuestionPrompt } = require("./prompt");
const { askLLM } = require("./llm");

const app = express();

app.use(express.json({
  limit: "2mb"
}));

app.get("/", (req, res) => {
  res.send("AI Browser Demo is running.");
});

app.post("/ask", async (req, res) => {
  const { url, question } = req.body;

  if (!url || !question) {
    return res.status(400).json({
      error: "请提供 url 和 question"
    });
  }

  try {
    const pageInfo = await extractPageInfo(url);
    const prompt = buildWebQuestionPrompt(pageInfo, question);
    const answer = await askLLM(prompt);

    res.json({
      url,
      question,
      answer,
      page: {
        title: pageInfo.title,
        description: pageInfo.description,
        headings: pageInfo.headings
      }
    });
  } catch (error) {
    console.error(error);

    res.status(500).json({
      error: "处理失败",
      message: error.message
    });
  }
});

const port = process.env.PORT || 3000;

app.listen(port, () => {
  console.log(`AI Browser Demo started at http://localhost:${port}`);
});

启动服务:

node src/index.js

测试接口:

curl -X POST http://localhost:3000/ask \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://example.com",
    "question": "请总结这个网页的主要内容"
  }'

返回示例:

{
  "url": "https://example.com",
  "question": "请总结这个网页的主要内容",
  "answer": "该网页主要用于示例展示,说明 Example Domain 可用于文档示例中引用...",
  "page": {
    "title": "Example Domain",
    "description": "",
    "headings": [
      {
        "tag": "h1",
        "text": "Example Domain"
      }
    ]
  }
}

八、增加“网页操作”能力

上面的版本主要是“阅读网页”。如果要让 AI 浏览器更进一步,就需要让它可以执行动作,例如:

  • 点击按钮;
  • 输入关键词;
  • 提交表单;
  • 截图;
  • 提取搜索结果;
  • 多页面跳转。

下面增加一个简单案例:自动打开搜索页面,输入关键词并提取搜索结果标题。

创建 src/search.js

const { chromium } = require("playwright");

async function searchBing(keyword) {
  const browser = await chromium.launch({
    headless: true
  });

  const page = await browser.newPage();

  try {
    await page.goto("https://www.bing.com", {
      waitUntil: "domcontentloaded"
    });

    await page.fill("input[name='q']", keyword);
    await page.keyboard.press("Enter");

    await page.waitForLoadState("networkidle");

    const results = await page.$$eval("li.b_algo", (items) => {
      return items.slice(0, 5).map((item) => {
        const titleEl = item.querySelector("h2");
        const linkEl = item.querySelector("h2 a");
        const descEl = item.querySelector(".b_caption p");

        return {
          title: titleEl ? titleEl.innerText.trim() : "",
          url: linkEl ? linkEl.href : "",
          description: descEl ? descEl.innerText.trim() : ""
        };
      });
    });

    return results.filter((item) => item.title && item.url);
  } finally {
    await browser.close();
  }
}

module.exports = {
  searchBing
};

然后在 index.js 中增加接口:

const { searchBing } = require("./search");

app.post("/search", async (req, res) => {
  const { keyword } = req.body;

  if (!keyword) {
    return res.status(400).json({
      error: "请提供 keyword"
    });
  }

  try {
    const results = await searchBing(keyword);

    res.json({
      keyword,
      results
    });
  } catch (error) {
    res.status(500).json({
      error: "搜索失败",
      message: error.message
    });
  }
});

测试:

curl -X POST http://localhost:3000/search \
  -H "Content-Type: application/json" \
  -d '{
    "keyword": "AI 浏览器 应用场景"
  }'

这样,我们就从“AI 阅读网页”扩展到了“AI 操作网页”。


九、进一步升级:让 AI 自动决定操作步骤

真正的 AI 浏览器并不是写死每一个操作,而是让模型根据页面状态和用户目标决定下一步动作。常见做法是给模型提供一组可用工具,例如:

[
  {
    "name": "open_url",
    "description": "打开指定网址"
  },
  {
    "name": "click",
    "description": "点击页面中的某个元素"
  },
  {
    "name": "type",
    "description": "向输入框输入文本"
  },
  {
    "name": "extract_text",
    "description": "提取当前页面文本"
  },
  {
    "name": "screenshot",
    "description": "获取当前页面截图"
  }
]

模型收到用户目标后,输出类似:

{
  "thought": "用户想搜索 AI 浏览器应用场景,需要先打开搜索引擎,然后输入关键词。",
  "action": "open_url",
  "params": {
    "url": "https://www.bing.com"
  }
}

程序执行后把结果再返回给模型,模型继续规划下一步。
这种模式就是常说的 Agent + Browser Tool

不过在实际项目中,不建议一开始就做全自动 Agent。因为全自动网页操作存在很多不确定性,例如:

  1. 页面结构复杂;
  2. 按钮文字可能重复;
  3. 弹窗、验证码、登录态会影响流程;
  4. 模型可能产生错误操作;
  5. 自动操作成本和延迟较高。

更稳妥的方式是先实现一些高频、可控的工具,例如:

  • 网页摘要;
  • 链接提取;
  • 表格提取;
  • 搜索结果聚合;
  • 页面截图;
  • 表单自动填写;
  • 指定网站的信息采集。

等这些能力稳定后,再逐步引入任务规划。


十、实战中的几个关键问题

1. 网页内容太长怎么办?

很多网页正文非常长,直接塞给模型会超出上下文限制,也会增加成本。常见解决方案包括:

  • 截断正文;
  • 按段落切分;
  • 使用 Embedding 做检索;
  • 先生成局部摘要,再合并摘要;
  • 只提取主要内容区域。

本文示例使用的是简单截断:

truncateText(cleanText(bodyText), 12000)

如果要做得更专业,可以使用分块摘要:

网页正文 → 切分为多个 chunk → 分别摘要 → 合并摘要 → 回答问题

2. 如何避免模型胡说?

提示词中一定要明确要求:

只基于网页内容回答,不要编造。
如果页面信息不足,请明确说明页面中没有足够信息。

同时,可以要求模型引用网页中的关键原文或标题:

回答时请引用网页中的相关段落或标题作为依据。

3. 如何提升网页提取质量?

简单使用 body.innerText 虽然方便,但可能包含导航栏、页脚、广告等无关内容。可以进一步优化:

  • 优先提取 article 标签;
  • 移除 navfooterscriptstyle
  • 根据文本密度判断正文区域;
  • 使用 Readability 算法;
  • 针对特定网站写适配器。

例如可以优先提取文章区域:

const articleText = await page
  .locator("article")
  .innerText()
  .catch(() => "");

如果 articleText 存在,就优先使用它。

4. 如何处理登录网站?

有些网站需要登录才能访问。可以使用 Playwright 保存登录态:

await context.storageState({
  path: "auth.json"
});

下次启动时加载:

const context = await browser.newContext({
  storageState: "auth.json"
});

这样就可以访问需要登录的页面,例如内部系统、管理后台、知识库等。

5. 如何保证安全?

AI 浏览器具备操作网页的能力,因此必须注意安全边界:

  • 不要让 AI 自动执行支付、删除、提交审批等高风险操作;
  • 对敏感动作增加人工确认;
  • 限制可访问域名;
  • 记录操作日志;
  • 避免泄露 Cookie、Token、内部网页内容;
  • 对用户输入 URL 做校验,防止 SSRF 风险。

十一、可落地的应用场景

AI 浏览器不是概念项目,它非常适合落地在以下场景:

1. 内容运营

运营人员每天需要阅读大量行业资讯、竞品文章、热点内容。AI 浏览器可以自动总结文章观点,提取标题、金句、传播角度,并生成二次创作文案。

2. 销售线索挖掘

输入公司官网,AI 浏览器可以提取公司介绍、业务范围、联系方式、产品信息,并生成客户画像。

3. 招聘信息整理

自动访问招聘网站或公司招聘页,提取岗位名称、薪资、地点、技能要求,并整理成表格。

4. 电商价格监控

定期访问商品页面,提取价格、库存、促销信息,并在价格变化时通知用户。

5. 企业内部知识库助手

对于 Confluence、飞书文档、Notion、语雀等知识库,AI 浏览器可以帮助员工快速阅读和总结页面内容。

6. 表单自动填写

对于重复性较强的后台录入工作,可以通过浏览器自动填写表单,减少人工操作。


十二、项目优化方向

如果你准备把这个 Demo 扩展成一个完整产品,可以从以下方向继续优化:

  1. 加入前端页面
    做一个输入 URL 和问题的界面,展示 AI 回答和网页结构。

  2. 支持流式输出
    使用 SSE 或 WebSocket,让答案逐字返回,体验更好。

  3. 增加网页截图能力
    有些页面视觉信息比文本更重要,可以截图后交给多模态模型分析。

  4. 引入向量检索
    对长网页或多个网页进行切片、向量化,支持跨页面问答。

  5. 实现工具调用机制
    让模型可以调用 open_urlclickextract 等工具。

  6. 增加任务队列
    对批量网页分析任务,可以使用 BullMQ、RabbitMQ 等队列系统。

  7. 增加权限控制
    不同用户只能访问自己的任务和网页数据。

  8. 支持浏览器会话复用
    避免每次请求都启动浏览器,提高性能。


十三、完整运行流程回顾

整个 AI 浏览器 Demo 的流程如下:

用户提交 URL 和问题
        ↓
Express 接口接收请求
        ↓
Playwright 打开网页
        ↓
提取标题、正文、链接、标题结构
        ↓
构造 Prompt
        ↓
调用大语言模型
        ↓
生成回答
        ↓
返回 JSON 结果

这个流程虽然简单,但已经具备 AI 浏览器的核心雏形。它不是单纯聊天,而是让 AI 获得了访问真实网页信息的能力。


十四、总结

AI 浏览器的核心价值在于:
把大语言模型的理解能力,与浏览器的网页访问和操作能力结合起来。

本文实现的 Demo 包含了几个关键模块:

  • 使用 Playwright 控制浏览器;
  • 提取网页标题、正文、链接和结构;
  • 使用 Prompt 让大模型理解网页;
  • 提供 HTTP API 供外部调用;
  • 扩展搜索和网页操作能力。

对于个人开发者来说,这个项目可以作为学习 AI Agent、网页自动化和大模型应用开发的入门案例。对于企业团队来说,它可以进一步演化为内部知识助手、自动化运营工具、销售线索系统或数据采集平台。

如果你想继续深入,可以尝试做三个增强功能:

  1. 支持网页截图并调用多模态模型分析;
  2. 支持长网页分块摘要和向量检索;
  3. 支持模型自动规划网页操作步骤。

当 AI 不只是回答问题,而是能真正打开网页、读取网页、理解网页并执行任务时,它就从“聊天助手”变成了“浏览器智能体”。这也是 AI 应用从内容生成走向任务执行的重要一步。

目录结构
全文