从零搭建一个会总结网页的浏览器助手:部署教程与源码分享
AI浏览器 部署完整教程|附源码
随着大模型能力的不断提升,“AI 浏览器”正在成为一个非常实用的应用方向。它不是简单地在浏览器里加一个聊天窗口,而是让 AI 能够理解网页内容、总结页面信息、提取重点、辅助搜索、生成问答,甚至对网页进行结构化分析。
本文将从零开始,带你完成一个简易版 AI 浏览器助手 的部署。该项目支持:
- 输入网页链接并抓取网页内容;
- 对网页正文进行清洗与提取;
- 调用大模型接口生成摘要;
- 支持基于网页内容进行问答;
- 提供前端页面交互;
- 支持本地部署与服务器部署;
- 附完整源码结构与核心代码。
本文适合有一定前端或后端基础的开发者阅读。如果你熟悉 JavaScript、Node.js 或者 Python,会更容易上手。
一、什么是 AI 浏览器?
AI 浏览器可以理解为“浏览器 + AI 助手”的组合。
传统浏览器主要负责网页访问、渲染和交互,而 AI 浏览器在此基础上增加了智能能力,例如:
-
网页总结
打开一篇长文章后,AI 可以快速总结核心观点。 -
网页问答
用户可以直接问:“这篇文章主要讲了什么?”“作者提出了哪些方案?” -
信息提取
从网页中提取标题、作者、发布时间、关键词、表格数据等。 -
辅助阅读
将复杂内容解释成通俗语言,或者翻译成其他语言。 -
智能搜索
不只是返回网页链接,而是直接整理搜索结果中的答案。
本文实现的是一个轻量级 AI 浏览器原型:用户输入网址,系统抓取网页内容,然后通过 AI 完成总结和问答。
二、项目技术栈
本项目采用前后端分离架构。
1. 前端技术
- HTML
- CSS
- JavaScript
- 原生 Fetch API
为了方便理解,本文不使用 Vue、React 等框架,而是采用最基础的 Web 技术实现界面。
2. 后端技术
- Node.js
- Express
- Axios
- Cheerio
其中:
Express用于搭建后端服务;Axios用于请求网页内容和调用 AI 接口;Cheerio用于解析 HTML,提取正文文本;- 大模型接口可替换为 OpenAI、通义千问、DeepSeek、Kimi、智谱等。
3. 部署方式
本文会介绍两种部署方式:
- 本地部署;
- Linux 服务器部署。
三、项目目录结构
我们先设计项目目录。
ai-browser/
├── server/
│ ├── app.js
│ ├── ai.js
│ ├── crawler.js
│ ├── package.json
│ └── .env
├── public/
│ ├── index.html
│ ├── style.css
│ └── main.js
└── README.md
目录说明:
| 文件 | 说明 |
|---|---|
server/app.js |
后端入口文件 |
server/ai.js |
AI 调用封装 |
server/crawler.js |
网页抓取与正文提取 |
server/.env |
环境变量配置 |
public/index.html |
前端页面 |
public/style.css |
页面样式 |
public/main.js |
前端交互逻辑 |
四、初始化项目
首先创建项目目录:
mkdir ai-browser
cd ai-browser
mkdir server public
进入 server 目录初始化 Node.js 项目:
cd server
npm init -y
安装依赖:
npm install express axios cheerio cors dotenv
如果需要开发时自动重启服务,可以安装:
npm install nodemon -D
修改 server/package.json:
{
"name": "ai-browser-server",
"version": "1.0.0",
"description": "AI Browser Backend",
"main": "app.js",
"scripts": {
"start": "node app.js",
"dev": "nodemon app.js"
},
"dependencies": {
"axios": "^1.6.0",
"cheerio": "^1.0.0",
"cors": "^2.8.5",
"dotenv": "^16.0.0",
"express": "^4.18.2"
},
"devDependencies": {
"nodemon": "^3.0.0"
}
}
五、配置环境变量
在 server 目录下创建 .env 文件:
PORT=3000
AI_API_KEY=你的大模型API_KEY
AI_API_URL=https://api.openai.com/v1/chat/completions
AI_MODEL=gpt-4o-mini
如果你使用的是其他模型服务,只需要修改 AI_API_URL 和 AI_MODEL 即可。
例如使用 DeepSeek 时可能类似:
AI_API_KEY=你的DeepSeek_API_KEY
AI_API_URL=https://api.deepseek.com/chat/completions
AI_MODEL=deepseek-chat
注意:不要把
.env文件上传到公开 GitHub 仓库,否则 API Key 可能泄露。
六、编写网页抓取模块
创建文件:
touch crawler.js
写入以下代码:
// server/crawler.js
const axios = require("axios");
const cheerio = require("cheerio");
/**
* 抓取网页 HTML
*/
async function fetchHtml(url) {
const response = await axios.get(url, {
timeout: 15000,
headers: {
"User-Agent":
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 Chrome/120 Safari/537.36",
Accept:
"text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8"
}
});
return response.data;
}
/**
* 提取网页正文内容
*/
function extractText(html) {
const $ = cheerio.load(html);
// 删除无关标签
$("script").remove();
$("style").remove();
$("noscript").remove();
$("iframe").remove();
$("svg").remove();
const title = $("title").text().trim();
let text = $("body").text();
// 清洗空白字符
text = text
.replace(/\s+/g, " ")
.replace(/\n+/g, "\n")
.trim();
// 限制长度,避免上下文过长
const maxLength = 12000;
if (text.length > maxLength) {
text = text.slice(0, maxLength);
}
return {
title,
text
};
}
/**
* 抓取并解析网页
*/
async function crawlPage(url) {
if (!/^https?:\/\//i.test(url)) {
throw new Error("URL 必须以 http:// 或 https:// 开头");
}
const html = await fetchHtml(url);
const result = extractText(html);
return result;
}
module.exports = {
crawlPage
};
这个模块完成了三件事:
- 请求目标网页;
- 使用 Cheerio 解析 HTML;
- 删除无用标签并提取正文文本。
需要说明的是,不同网站的 HTML 结构不同,本文采用通用提取方式。如果是生产环境,可以结合 Readability、Mercury Parser 或自定义规则提升正文提取质量。
七、封装 AI 调用模块
创建文件:
touch ai.js
写入代码:
// server/ai.js
const axios = require("axios");
const AI_API_KEY = process.env.AI_API_KEY;
const AI_API_URL = process.env.AI_API_URL;
const AI_MODEL = process.env.AI_MODEL;
/**
* 调用大模型
*/
async function callAI(messages) {
if (!AI_API_KEY) {
throw new Error("缺少 AI_API_KEY,请检查 .env 配置");
}
const response = await axios.post(
AI_API_URL,
{
model: AI_MODEL,
messages,
temperature: 0.3
},
{
headers: {
Authorization: `Bearer ${AI_API_KEY}`,
"Content-Type": "application/json"
},
timeout: 60000
}
);
return response.data.choices[0].message.content;
}
/**
* 总结网页内容
*/
async function summarizePage(title, text) {
const messages = [
{
role: "system",
content:
"你是一个专业的网页阅读助手,擅长总结网页内容,请用中文输出结构清晰、简洁准确的摘要。"
},
{
role: "user",
content: `
请总结以下网页内容:
网页标题:
${title}
网页正文:
${text}
请按照以下格式输出:
1. 核心摘要
2. 主要观点
3. 关键信息
4. 适合谁阅读
`
}
];
return await callAI(messages);
}
/**
* 基于网页内容问答
*/
async function askPage(title, text, question) {
const messages = [
{
role: "system",
content:
"你是一个网页内容问答助手。你只能根据用户提供的网页内容回答问题。如果内容中没有答案,请明确说明无法从网页内容中判断。"
},
{
role: "user",
content: `
网页标题:
${title}
网页正文:
${text}
用户问题:
${question}
请基于网页正文回答。
`
}
];
return await callAI(messages);
}
module.exports = {
summarizePage,
askPage
};
这里我们封装了两个能力:
summarizePage:总结网页;askPage:针对网页内容问答。
八、编写后端入口文件
创建 app.js:
touch app.js
写入代码:
// server/app.js
require("dotenv").config();
const express = require("express");
const cors = require("cors");
const path = require("path");
const { crawlPage } = require("./crawler");
const { summarizePage, askPage } = require("./ai");
const app = express();
app.use(cors());
app.use(express.json({ limit: "2mb" }));
// 静态资源目录
app.use(express.static(path.join(__dirname, "../public")));
/**
* 健康检查接口
*/
app.get("/api/health", (req, res) => {
res.json({
code: 0,
message: "AI Browser Server is running"
});
});
/**
* 抓取网页并总结
*/
app.post("/api/summarize", async (req, res) => {
try {
const { url } = req.body;
if (!url) {
return res.status(400).json({
code: 1,
message: "缺少 url 参数"
});
}
const page = await crawlPage(url);
const summary = await summarizePage(page.title, page.text);
res.json({
code: 0,
data: {
url,
title: page.title,
textLength: page.text.length,
summary
}
});
} catch (error) {
console.error(error);
res.status(500).json({
code: 1,
message: error.message || "服务器错误"
});
}
});
/**
* 基于网页内容问答
*/
app.post("/api/ask", async (req, res) => {
try {
const { url, question } = req.body;
if (!url || !question) {
return res.status(400).json({
code: 1,
message: "缺少 url 或 question 参数"
});
}
const page = await crawlPage(url);
const answer = await askPage(page.title, page.text, question);
res.json({
code: 0,
data: {
url,
title: page.title,
question,
answer
}
});
} catch (error) {
console.error(error);
res.status(500).json({
code: 1,
message: error.message || "服务器错误"
});
}
});
const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
console.log(`AI Browser Server running at http://localhost:${PORT}`);
});
到这里,后端接口已经基本完成。
我们提供了两个主要 API:
| 接口 | 方法 | 说明 |
|---|---|---|
/api/summarize |
POST | 总结网页内容 |
/api/ask |
POST | 基于网页内容问答 |
/api/health |
GET | 健康检查 |
九、编写前端页面
回到项目根目录下的 public 目录。
创建 index.html:
AI 浏览器助手
AI 浏览器助手
输入网页链接,让 AI 帮你总结、分析和问答
AI 输出
暂无内容
十、编写页面样式
创建 style.css:
/* public/style.css */
* {
box-sizing: border-box;
}
body {
margin: 0;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "PingFang SC",
"Microsoft YaHei", sans-serif;
background: #f4f6fb;
color: #222;
}
.app {
max-width: 960px;
margin: 0 auto;
padding: 40px 20px;
}
.header {
text-align: center;
margin-bottom: 32px;
}
.header h1 {
font-size: 36px;
margin-bottom: 8px;
}
.header p {
color: #666;
}
.card {
background: #fff;
border-radius: 16px;
padding: 24px;
margin-bottom: 20px;
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.06);
}
label {
display: block;
font-weight: 600;
margin-bottom: 12px;
}
.url-box {
display: flex;
gap: 12px;
}
input,
textarea {
width: 100%;
border: 1px solid #dcdfe6;
border-radius: 10px;
padding: 14px;
font-size: 15px;
outline: none;
}
textarea {
min-height: 100px;
resize: vertical;
}
input:focus,
textarea:focus {
border-color: #4f7cff;
}
button {
border: none;
background: #4f7cff;
color: #fff;
padding: 0 24px;
border-radius: 10px;
font-size: 15px;
cursor: pointer;
white-space: nowrap;
}
button:hover {
background: #345eea;
}
.result-card h2 {
margin-top: 0;
}
pre {
white-space: pre-wrap;
word-break: break-word;
line-height: 1.8;
background: #f8f9fc;
padding: 18px;
border-radius: 12px;
min-height: 200px;
}
.loading {
color: #4f7cff;
margin-bottom: 12px;
}
.hidden {
display: none;
}
@media (max-width: 640px) {
.url-box {
flex-direction: column;
}
button {
height: 44px;
}
}
十一、编写前端交互逻辑
创建 main.js:
// public/main.js
const urlInput = document.getElementById("urlInput");
const questionInput = document.getElementById("questionInput");
const summaryBtn = document.getElementById("summaryBtn");
const askBtn = document.getElementById("askBtn");
const result = document.getElementById("result");
const loading = document.getElementById("loading");
function setLoading(status) {
if (status) {
loading.classList.remove("hidden");
} else {
loading.classList.add("hidden");
}
}
function showResult(text) {
result.textContent = text;
}
async function postJSON(url, data) {
const response = await fetch(url, {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify(data)
});
return await response.json();
}
summaryBtn.addEventListener("click", async () => {
const url = urlInput.value.trim();
if (!url) {
alert("请输入网页链接");
return;
}
try {
setLoading(true);
showResult("正在抓取网页并生成摘要...");
const res = await postJSON("/api/summarize", { url });
if (res.code !== 0) {
throw new Error(res.message);
}
showResult(
`网页标题:${res.data.title}\n\n` +
`正文长度:${res.data.textLength}\n\n` +
`${res.data.summary}`
);
} catch (error) {
showResult("请求失败:" + error.message);
} finally {
setLoading(false);
}
});
askBtn.addEventListener("click", async () => {
const url = urlInput.value.trim();
const question = questionInput.value.trim();
if (!url) {
alert("请输入网页链接");
return;
}
if (!question) {
alert("请输入问题");
return;
}
try {
setLoading(true);
showResult("正在分析网页并回答问题...");
const res = await postJSON("/api/ask", {
url,
question
});
if (res.code !== 0) {
throw new Error(res.message);
}
showResult(
`网页标题:${res.data.title}\n\n` +
`问题:${res.data.question}\n\n` +
`回答:\n${res.data.answer}`
);
} catch (error) {
showResult("请求失败:" + error.message);
} finally {
setLoading(false);
}
});
前端逻辑很简单:
- 用户输入 URL;
- 点击“总结网页”调用
/api/summarize; - 输入问题后点击“提交问题”调用
/api/ask; - 将 AI 返回结果展示到页面中。
十二、本地运行项目
进入 server 目录:
cd server
npm run dev
如果不使用 nodemon,可以执行:
npm start
启动成功后,你会看到:
AI Browser Server running at http://localhost:3000
打开浏览器访问:
http://localhost:3000
输入一个网页地址,例如:
https://example.com
点击“总结网页”,等待 AI 返回结果即可。
十三、服务器部署教程
下面以 Ubuntu 服务器为例进行部署。
1. 安装 Node.js
推荐使用 Node.js 18 或以上版本。
sudo apt update
sudo apt install -y curl
curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash -
sudo apt install -y nodejs
查看版本:
node -v
npm -v
2. 上传项目代码
可以通过 Git 上传:
git clone https://你的仓库地址/ai-browser.git
cd ai-browser/server
也可以通过 scp 上传:
scp -r ai-browser root@你的服务器IP:/www/wwwroot/
3. 安装依赖
cd /www/wwwroot/ai-browser/server
npm install
4. 配置环境变量
编辑 .env:
vim .env
写入:
PORT=3000
AI_API_KEY=你的API_KEY
AI_API_URL=https://api.openai.com/v1/chat/completions
AI_MODEL=gpt-4o-mini
保存退出。
5. 使用 PM2 守护进程
安装 PM2:
sudo npm install pm2 -g
启动项目:
pm2 start app.js --name ai-browser
查看运行状态:
pm2 list
查看日志:
pm2 logs ai-browser
设置开机自启:
pm2 startup
pm2 save
十四、使用 Nginx 反向代理
如果你希望通过域名访问,例如:
https://ai.example.com
可以使用 Nginx 进行反向代理。
安装 Nginx:
sudo apt install -y nginx
创建配置文件:
sudo vim /etc/nginx/conf.d/ai-browser.conf
写入:
server {
listen 80;
server_name ai.example.com;
location / {
proxy_pass http://127.0.0.1:3000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
检查配置:
sudo nginx -t
重启 Nginx:
sudo systemctl restart nginx
此时访问:
http://ai.example.com
即可打开 AI 浏览器助手。
如果需要 HTTPS,可以使用 Certbot 申请免费 SSL 证书:
sudo apt install -y certbot python3-certbot-nginx
sudo certbot --nginx -d ai.example.com
十五、常见问题与解决方案
1. 网页抓取失败怎么办?
可能原因包括:
- 目标网站禁止爬虫;
- 页面需要登录;
- 页面内容由 JavaScript 动态渲染;
- 网络访问受限;
- 网站有反爬策略。
解决方案:
- 更换 User-Agent;
- 使用 Playwright 或 Puppeteer 渲染页面;
- 对特定网站编写专门解析规则;
- 增加请求重试机制。
2. AI 返回内容太慢怎么办?
可能原因:
- 网页正文太长;
- 模型接口响应慢;
- 网络延迟较高。
优化方案:
- 限制正文长度;
- 先对正文分段摘要,再进行总摘要;
- 使用响应速度更快的模型;
- 增加缓存机制。
3. 摘要结果不准确怎么办?
可以优化 Prompt,例如要求模型:
- 不要编造网页中没有的信息;
- 输出引用依据;
- 按标题、小节、重点进行总结;
- 对不确定内容明确说明。
4. API Key 泄露怎么办?
如果 API Key 泄露,应立即:
- 到模型平台后台删除旧 Key;
- 重新创建新 Key;
- 修改服务器
.env; - 重启服务。
十六、项目可扩展方向
这个 AI 浏览器只是基础版本,后续可以扩展很多实用能力。
1. 浏览器插件版本
可以开发 Chrome Extension,实现:
- 当前网页一键总结;
- 右侧边栏 AI 助手;
- 选中文本解释;
- 网页翻译;
- 文章收藏与知识库沉淀。
2. 加入向量数据库
对于长网页或多个网页,可以使用向量数据库实现 RAG 检索增强。
可选方案:
- Chroma
- Milvus
- Qdrant
- Pinecone
- pgvector
流程如下:
- 抓取网页;
- 分段切片;
- 生成 Embedding;
- 存入向量数据库;
- 用户提问时召回相关片段;
- 再交给大模型回答。
3. 支持多轮对话
当前问答每次都会重新抓取网页,效率不高。可以增加会话 ID,将网页内容缓存起来,实现连续对话。
4. 支持搜索引擎聚合
可以接入搜索 API,让 AI 自动搜索多个网页并整合答案。
5. 增加登录系统
如果要面向用户开放,需要增加:
- 用户注册登录;
- 调用次数限制;
- 会员权限;
- 用量统计;
- 风控系统。
十七、生产环境安全建议
如果项目要正式上线,建议至少处理以下问题:
-
限制 URL 类型
防止用户请求内网地址,避免 SSRF 风险。 -
接口限流
防止恶意刷接口导致 API 费用暴涨。 -
内容缓存
同一个 URL 不要重复抓取和调用模型。 -
错误日志记录
便于定位线上问题。 -
API Key 后端保存
不要把 Key 暴露在前端。 -
增加超时机制
避免请求长时间挂起。 -
过滤敏感地址
禁止访问localhost、127.0.0.1、内网 IP 等。
下面是一个简单的 URL 安全校验示例:
function isSafeUrl(url) {
try {
const parsed = new URL(url);
const hostname = parsed.hostname;
const blockedHosts = [
"localhost",
"127.0.0.1",
"0.0.0.0"
];
if (blockedHosts.includes(hostname)) {
return false;
}
if (!["http:", "https:"].includes(parsed.protocol)) {
return false;
}
return true;
} catch {
return false;
}
}
实际生产环境还需要进一步判断内网 IP 段,例如:
10.0.0.0/8172.16.0.0/12192.168.0.0/16
十八、完整部署流程总结
完整流程如下:
# 1. 创建项目
mkdir ai-browser
cd ai-browser
mkdir server public
# 2. 初始化后端
cd server
npm init -y
# 3. 安装依赖
npm install express axios cheerio cors dotenv
# 4. 编写 app.js、ai.js、crawler.js
# 5. 配置 .env
vim .env
# 6. 编写前端 index.html、style.css、main.js
# 7. 本地运行
npm run dev
# 8. 服务器部署
pm2 start app.js --name ai-browser
# 9. Nginx 反向代理
sudo nginx -t
sudo systemctl restart nginx
十九、结语
本文完整实现了一个轻量级 AI 浏览器助手,从项目初始化、网页抓取、正文提取、AI 总结、网页问答,到本地运行和服务器部署,整个流程都已经覆盖。
这个项目虽然简单,但已经具备 AI 浏览器的核心雏形:
- 能读取网页;
- 能理解网页;
- 能生成摘要;
- 能基于网页内容回答问题;
- 能通过 Web 页面提供交互。
如果你想继续深入,可以将它扩展为 Chrome 插件、知识库系统、智能搜索引擎,甚至做成团队内部的资料阅读助手。对于个人开发者来说,这是一个非常适合练手和商业化尝试的 AI 应用方向。