189 lines
4.6 KiB
Markdown
189 lines
4.6 KiB
Markdown
# 网站接入店闪扩展说明
|
||
|
||
这个扩展已经提供网站侧调用接口。网站点击“开始”时,可以让扩展执行和 popup 手动点击“立即爬取”一样的流程:打开新浏览器窗口、进入平台后台、抓取数据。抓取完成后,扩展会通过长连接把结果推回网站。
|
||
|
||
## 1. 先配置允许连接的网站域名
|
||
|
||
扩展的 `manifest.config.ts` 里有:
|
||
|
||
```ts
|
||
externally_connectable: {
|
||
matches: [
|
||
"http://localhost:3000/*",
|
||
]
|
||
}
|
||
```
|
||
|
||
把你的网站域名加进去,例如:
|
||
|
||
```ts
|
||
externally_connectable: {
|
||
matches: [
|
||
"http://localhost:3000/*",
|
||
"https://your-site.com/*",
|
||
]
|
||
}
|
||
```
|
||
|
||
改完扩展后需要重新 `pnpm run build`,并在 Chrome 扩展管理页重新加载扩展。
|
||
|
||
## 2. 网站侧需要知道扩展 ID
|
||
|
||
Chrome 扩展管理页打开“开发者模式”,复制这个扩展的 ID:
|
||
|
||
```ts
|
||
const EXTENSION_ID = "这里换成你的扩展ID";
|
||
```
|
||
|
||
开发环境如果每次扩展 ID 变化,建议给扩展配置固定 key,或者每次复制新的 ID 到网站项目配置里。
|
||
|
||
## 3. 推荐的网站侧接入代码
|
||
|
||
网站页面加载后先建立长连接,用来接收扩展推送的进度和最终结果。
|
||
|
||
```ts
|
||
const EXTENSION_ID = "这里换成你的扩展ID";
|
||
|
||
type DianshanMessage = {
|
||
ok: boolean;
|
||
type?: string;
|
||
data?: {
|
||
state: any | null;
|
||
result: Record<string, unknown> | null;
|
||
};
|
||
error?: string;
|
||
};
|
||
|
||
let port: chrome.runtime.Port | null = null;
|
||
|
||
export function connectDianshanExtension() {
|
||
port = chrome.runtime.connect(EXTENSION_ID, { name: "DIANSHAN_CRAWL" });
|
||
|
||
port.onMessage.addListener((message: DianshanMessage) => {
|
||
console.log("[dianshan]", message);
|
||
|
||
if (message.type === "DIANSHAN_CRAWL_STATE") {
|
||
// 可选:更新网站上的进度 UI
|
||
return;
|
||
}
|
||
|
||
if (message.type === "DIANSHAN_CRAWL_DONE") {
|
||
// 抓取完成,最终数据在 message.data.result
|
||
console.log("抓取结果", message.data?.result);
|
||
return;
|
||
}
|
||
|
||
if (message.type === "DIANSHAN_CRAWL_FAILED") {
|
||
// 抓取失败,可展示 message.data.state.steps 里的失败原因
|
||
console.error("抓取失败", message.data?.state);
|
||
return;
|
||
}
|
||
|
||
if (message.type === "DIANSHAN_CRAWL_CANCELED" || message.type === "DIANSHAN_CRAWL_CLEARED") {
|
||
// 用户取消或任务被清空
|
||
console.log("抓取已取消");
|
||
}
|
||
});
|
||
|
||
port.onDisconnect.addListener(() => {
|
||
port = null;
|
||
});
|
||
}
|
||
```
|
||
|
||
## 4. 网站点击“开始抓取”
|
||
|
||
按钮点击时调用:
|
||
|
||
```ts
|
||
export async function startDianshanCrawl(platformId = "Shopee") {
|
||
const response = await chrome.runtime.sendMessage(EXTENSION_ID, {
|
||
type: "DIANSHAN_START_CRAWL",
|
||
payload: { platformId },
|
||
});
|
||
|
||
if (!response?.ok) {
|
||
throw new Error(response?.error ?? "启动抓取失败");
|
||
}
|
||
|
||
return response.data;
|
||
}
|
||
```
|
||
|
||
效果等同于用户打开 popup 后手动点击“立即爬取”。如果当前已经有 running/paused 的任务,扩展会直接返回当前任务,不会重复打开多个抓取窗口。
|
||
|
||
## 5. 查询当前状态
|
||
|
||
```ts
|
||
export async function getDianshanCrawlState() {
|
||
return chrome.runtime.sendMessage(EXTENSION_ID, {
|
||
type: "DIANSHAN_GET_CRAWL_STATE",
|
||
});
|
||
}
|
||
```
|
||
|
||
## 6. 网站侧取消抓取
|
||
|
||
```ts
|
||
export async function cancelDianshanCrawl() {
|
||
return chrome.runtime.sendMessage(EXTENSION_ID, {
|
||
type: "DIANSHAN_CANCEL_CRAWL",
|
||
});
|
||
}
|
||
```
|
||
|
||
取消后扩展会清空 `crawlTaskState`,并关闭扩展自动打开的浏览器窗口。
|
||
|
||
## 7. 返回数据结构
|
||
|
||
长连接收到 `DIANSHAN_CRAWL_DONE` 时,数据大致是:
|
||
|
||
```ts
|
||
{
|
||
ok: true,
|
||
type: "DIANSHAN_CRAWL_DONE",
|
||
data: {
|
||
state: {
|
||
id: "Shopee-...",
|
||
platformId: "Shopee",
|
||
platformName: "Shopee 后台",
|
||
status: "completed",
|
||
steps: [
|
||
{
|
||
name: "数据看板",
|
||
uniqueKey: "databoard",
|
||
status: "success",
|
||
result: {}
|
||
}
|
||
]
|
||
},
|
||
result: {
|
||
databoard: {
|
||
name: "数据看板",
|
||
status: "success",
|
||
result: {}
|
||
},
|
||
adscenter: {
|
||
name: "广告中心",
|
||
status: "success",
|
||
result: {}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
网站项目里一般用 `message.data.result` 入库或展示即可;如果要展示进度,用 `message.data.state.steps`。
|
||
|
||
## 8. 最小使用流程
|
||
|
||
```ts
|
||
connectDianshanExtension();
|
||
|
||
document.querySelector("#start")?.addEventListener("click", async () => {
|
||
await startDianshanCrawl("Shopee");
|
||
});
|
||
```
|
||
|
||
注意:网站必须运行在 `externally_connectable.matches` 配置过的域名下,否则 Chrome 会拒绝调用扩展。
|