
浏览器插件开发实战:导出PDD商品评论
做电商的人,大概率都干过这件事:
打开商品评论页,往下翻,复制几条评论,贴进表格,再开始分类、统计、分析。
前两次还行。
第十次就会开始怀疑人生。
所以这次,直接上工具。
这篇文章拿一个真实小项目做例子,带你做一个 Chrome 浏览器插件:在 PDD 商品评论页右键一下,直接导出评论数据。
先说明下边界:
文章里会贴可公开的插件代码 因为那部分最依赖真实页面结构,也是定制开发里最有价值的部分
如果你是新手,这篇适合入门。
如果你是做电商、运营、数据整理、自动化提效的,这篇也能让你快速判断:这类插件到底值不值得做。
这插件能干嘛
目标很直接:
在 PDD 商品评论页里,右键点击页面,选择“导出评论”,插件自动完成下面几件事:
把评论页面自动滚到底 等评论加载完整 提取评论数据 整理成 JSON 下载到本地
导出的字段目前包括:
商品 ID评论内容 图片/视频信息 追评信息
别看功能不大,里面已经把浏览器插件开发里最常见的一条链路走完了:
插件配置 右键菜单 页面脚本注入 指定站点权限 动态页面滚动 数据导出下载
拿它当入门项目,刚好。
先看项目结构
这个项目很轻,核心文件就几个:
pdd-comment
├─ manifest.json
├─ background.js
├─ content.js
├─ export-helpers.js
└─ icons
怎么理解这几个文件?
manifest.json:插件身份证,告诉浏览器“我是谁,我能干什么,我能去哪儿”
background.js:后台调度员,负责创建右键菜单、监听点击事件
content.js:真正进到评论页里干活的脚本,负责滚动、提取、导出、提示
export-helpers.js:把原始数据整理成你真正想要的字段
一句话总结:
background.js 负责喊开始,content.js 负责下场干活。
第一步:把插件身份报上去
Chrome 插件的入口是 manifest.json。
没有它,浏览器连你是谁都不知道。
这里是当前项目的核心配置:
{
"manifest_version": 3,
"name": "PDD 评论导出助手",
"description": "在拼多多评论页右键导出",
"version": "0.1.0",
"permissions": [
"contextMenus",
"tabs",
"scripting"
],
"host_permissions": [
"https://mobile.yangkeduo.com/*",
"https://mobile.pinduoduo.com/*"
],
"background": {
"service_worker": "background.js"
},
"icons": {
"48": "icons/icon48.png",
"128": "icons/icon128.png"
}
}
这里有几个新手必须认识的点:
manifest_version: 3:现在主流是MV3contextMenus:让你能加右键菜单scripting:让你能往页面里注入脚本host_permissions:声明你能访问哪些网站service_worker:后台脚本入口
很多新手一上来最容易翻车的地方,不是代码写错,而是权限没配对。
菜单能显示,不代表脚本能跑。 脚本能跑,不代表页面数据拿得到。
插件开发这事,第一关往往是配置,不是逻辑。
第二步:先把右键菜单做出来
插件入口有很多种。
可以做弹窗,可以做悬浮按钮,也可以搞快捷键。
但这个项目选右键菜单,原因很简单:
用户不用学 页面不用改 成本很低 放在评论页里刚刚好
后台脚本代码如下:
const MENU_ID = 'pdd-export-orders-comment';
functioncreateContextMenu() {
chrome.contextMenus.removeAll(() => {
chrome.contextMenus.create({
id: MENU_ID,
title: '导出评论',
contexts: ['page'],
documentUrlPatterns: [
'https://mobile.yangkeduo.com/goods_comments.htm*',
'https://mobile.pinduoduo.com/goods_comments.htm*'
]
});
});
}
chrome.runtime.onInstalled.addListener(() => {
createContextMenu();
});
chrome.runtime.onStartup.addListener(() => {
createContextMenu();
});
这段代码的意思不复杂:
浏览器启动时,把一个叫“导出评论”的菜单挂上去。
但不是全网都挂。
只在 PDD 商品评论页挂。
这点很重要。插件越克制,越像工具;插件到处乱出现,就很像打扰。
第三步:用户点了菜单,接下来怎么办
点菜单不是重点。
重点是,点完以后,谁进页面里拿数据。
答案是:注入脚本。
代码如下:
chrome.contextMenus.onClicked.addListener((info, tab) => {
if (info.menuItemId !== MENU_ID || !tab?.id) {
return;
}
chrome.scripting.executeScript({
target: { tabId: tab.id },
files: ['export-helpers.js', 'content.js'],
world: 'MAIN'
}).catch((error) => {
console.warn('执行导出脚本失败:', error?.message || error);
});
});
这里可以顺手理解一个浏览器插件的常识:
background.js 不直接处理页面内容,它更像指挥员。
真正看页面、滚页面、读页面的,是注入进去的 content.js。
另外这里用了 world: 'MAIN'。
这不是装饰项。
很多站点的数据挂在页面自己的运行环境里,脚本如果跑在隔离环境,有时候只能看见空气。
第四步:为什么不能直接复制评论
很多人第一次做这种需求,都会想:
“评论不是就在页面上吗?直接抓文字不就完了?”
理论上可以。
实际上通常会翻车。
因为真实页面往往是这样的:
首屏只加载一部分评论 继续下滑才会请求下一批 图片、视频、追评不一定都在可见文本里 页面改版后,DOM 结构可能立刻变
所以要做一个能用的导出工具,至少得解决两件事:
先把评论尽量加载全 再从相对稳定的位置拿数据
这个项目里,第一步先交给自动滚动。
第五步:先把页面滚到底
评论没加载完,导出就没有意义。
最直白的办法,就是一直往下滚,直到页面出现“没有更多评价”。
代码可以这么写:
asyncfunctionscrollToEndByText() {
const targetText = '没有更多评价';
const maxAttempts = 1000;
const waitTime = 1000;
for (let i = 1; i <= maxAttempts; i++) {
window.scrollTo(0, document.body.scrollHeight);
awaitnewPromise((resolve) => {
setTimeout(resolve, waitTime);
});
const pageText = document.body.innerText;
if (pageText.includes(targetText)) {
return;
}
}
window.scrollTo(0, document.body.scrollHeight);
}
这段代码的气质很朴素,但很实战。
它不花哨,就是不停地下拉、等待、检查,直到发现页面告诉你:别翻了,真没了。
当然,真做商用时一般还会继续补:
超时提示 进度提示 文案兼容 网络异常处理 手动停止
这些就是“能跑”和“好用”之间的差距。
第六步:真正难的不是导出,是找数据
滚到底只是前菜。
真正难的,是从页面里把评论数据拿出来。
这里通常有两种路线:
从 DOM 文本里抠 从页面内部状态里拿
第一种简单,适合快速验证。
第二种稳定,适合真做工具。
这个项目走的是第二种:从页面内部状态里定位评论列表,再做字段整理。
但这部分核心实现不放出来,只给一个结构示意:
functiongetCommentList() {
const root = findPageCommentContainer();
if (!root) {
thrownewError('未找到评论容器');
}
// 核心逻辑略:
// 1. 定位页面框架内部节点
// 2. 查找评论列表对应的数据路径
// 3. 返回原始评论数据
return commentList;
}
为什么这段不贴?
因为它和具体页面结构强绑定。
今天能用,明天页面一改版,路径就可能变。
这也是为什么很多人觉得“网页数据导出不就是几行 JS”,结果一做就发现,真正值钱的不是按钮,而是适配。
第七步:拿到数据后,别急着一股脑导出
原始数据通常又长又乱。
直接扔出去,后面用的人大概率还得再洗一遍。
所以更合理的做法,是先整理成你真正关心的字段:
functionbuildRows(commentList) {
return commentList.map((item) => {
return {
goodsId: item.goodsId,
comment: item.comment,
picAndVideo: item.picAndVideo,
append: item.append
};
});
}
现在这份插件保留了四个字段:
goodsIdcommentpicAndVideoappend
够做基础分析了。
如果业务再深一点,通常还会继续加:
评论时间 用户昵称 SKU 信息 星级标签 图片链接 视频链接 关键词结果 情感分析结果
字段设计这事,没有标准答案。
只有一个标准:后面的人拿到数据,能不能直接用。
第八步:导出文件,本质上就是造一个下载链接
浏览器里导出本地文件,常见写法就是 Blob + a 标签。
代码如下:
functiondownload(rows) {
const blob = new Blob(
[JSON.stringify(rows, null, 2)],
{ type: 'text/json;charset=utf-8;' }
);
const url = URL.createObjectURL(blob);
const filename = `${rows[0].goodsId}.json`;
const link = document.createElement('a');
link.href = url;
link.download = filename;
link.style.display = 'none';
document.body.appendChild(link);
link.click();
link.remove();
URL.revokeObjectURL(url);
}
这版导出的是 JSON。
原因也简单:开发时最省事,字段最完整,后续要转 Excel、做清洗、喂给 AI 都方便。
如果你的业务更偏运营同学直接使用,那往往会继续加:
CSV导出Excel导出一键上传到后台
工具做到最后,格式从来不是技术问题,是使用场景问题。
第九步:别让用户对着控制台猜结果
很多开发者写工具时有个习惯:
报错了,console.log成功了,console.log结束了,还是 console.log
然后把用户留在页面上发呆。
这显然不合适。
所以这个插件加了一个很轻的提示浮层:
functionshowToast(message) {
const id = 'pdd-export-toast';
const existed = document.getElementById(id);
if (existed) {
existed.remove();
}
const toast = document.createElement('div');
toast.id = id;
toast.textContent = message;
toast.style.position = 'fixed';
toast.style.top = '20px';
toast.style.right = '20px';
toast.style.zIndex = '999999';
toast.style.padding = '10px 14px';
toast.style.fontSize = '14px';
toast.style.color = '#fff';
toast.style.background = 'rgba(0, 0, 0, 0.75)';
toast.style.borderRadius = '6px';
document.body.appendChild(toast);
window.setTimeout(() => {
toast.remove();
}, 2400);
}
这类提示虽然简单,但很有用。
用户不需要懂脚本、不需要开控制台,也知道到底成功了没有。
别小看这种细节。
很多工具最后拼的,不是“能不能跑”,而是“别人愿不愿意继续用”。
第十步:把整条流程串起来
最后,页面脚本主流程大概是这样:
(async () => {
try {
await scrollToEndByText();
const commentList = getCommentList();
const rows = buildRows(commentList);
if (!rows.length) {
thrownewError('未提取到可导出的评论记录');
}
download(rows);
showToast(`导出成功,共 ${rows.length} 条记录`);
} catch (error) {
console.error(error);
showToast(`导出失败:${error.message}`);
}
})();
流程其实不复杂:
滚动到底,拿数据,整理字段,导出文件,给个提示。
但这类项目真正的难点,从来不是主流程写不出来。
而是:
页面到底怎么拿数据 平台改版后怎么适配 字段要不要补 批量导出怎么做 导出格式给谁用
代码只是开始,交付才是正题。
新手最容易踩的几个坑
1. 权限写了,但没写对
插件开发里,很多“没反应”都是权限问题。
不是逻辑没跑,是浏览器压根不让你跑。
2. 页面没加载完,就开始导出
结果当然就是只导出前几条评论。
这个坑非常常见。
3. 只会抓 DOM,不会找真实数据源
页面一改版,脚本立刻废一半。
4. 字段没提前定好
你以为导出评论就结束了,运营同学会告诉你:
“能不能顺便带上 SKU、时间、图片链接、追评、差评标签、Excel 格式?”
5. 没有用户提示
工具不是你自己偷偷用,别人用的时候,得知道现在发生了什么。
这类插件,适合拿去做什么
评论导出只是入口。
同样的思路,可以继续做很多业务工具:
商品评论采集 订单信息导出 店铺页面数据整理 竞品评论分析 网页内容转 Excel 客服记录归档 内部运营自动化
本质上都是一件事:
把原来靠人手一点点搬运的数据,交给插件去做。
人负责判断。 工具负责重复。
这就对了。
为什么这类需求最后经常变成定制开发
因为每个人嘴里说的“导出评论”,都不是一回事。
有人只要评论文本。 有人要图片和视频。 有人要 Excel。 有人要批量跑多个商品。 有人要自动翻页。 有人要对接自己后台。 有人要直接做 AI 分析。
所以这类需求真正做起来,拼的不是“能不能写插件”。
拼的是:
对目标页面的理解 对字段的拆分能力 对异常和改版的处理 对交付场景的判断
这也是最适合定制开发的地方。
因为复制一段代码很容易。
复制一套稳定可用的适配逻辑,不容易。
适合付费定制的需求
如果你刚好有下面这些需求,做定制插件通常很合适:
想从网页后台批量导出数据 想把重复复制粘贴变成一键操作 想导出成 Excel、CSV、JSON想整理商品、订单、评论、客户信息 想接自己的后台系统 想做电商运营自动化 想做评论数据的 AI 分析
这类需求的价值,不在“写个按钮”。
而在于把每天重复、机械、容易出错的动作,变成一个稳定工具。
最后
这个 PDD 评论导出插件,拿来做浏览器插件入门,很合适。
它不大,但足够完整。
从插件配置,到右键菜单,到脚本注入,到页面滚动,到数据导出,整条链路都走了一遍。
如果你是新手,可以照着这个思路练手。
如果你已经在做业务,也可以直接把它当成一个判断标准:
凡是网页里重复点、重复翻、重复复制、重复整理的动作,基本都值得先问一句:
“这事能不能做成工具?”
大多数时候,答案是:能。
需要定制浏览器插件、网页数据导出工具、电商运营自动化工具,可以沟通具体场景。
支持方向包括:
Chrome 插件开发 电商页面数据导出 评论/订单/商品信息采集 Excel/CSV/JSON整理AI 评论分析 内部运营工具定制 网页自动化流程开发
工具写得好,最明显的效果通常不是“技术很强”。
而是团队里再也没人愿意手工复制评论了。
如果你有需要定制的产品,可以关注公众号私信我~
夜雨聆风