1688-cli 0.1.24 → 0.1.26
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +125 -39
- package/CHANGELOG.md +61 -0
- package/README.md +141 -64
- package/dist/cli.js +13 -0
- package/dist/cli.js.map +1 -1
- package/dist/commands/cart-add.js +224 -133
- package/dist/commands/cart-add.js.map +1 -1
- package/dist/commands/cart-list.js +22 -3
- package/dist/commands/cart-list.js.map +1 -1
- package/dist/commands/cart-remove.js +5 -0
- package/dist/commands/cart-remove.js.map +1 -1
- package/dist/commands/image-search.js +44 -11
- package/dist/commands/image-search.js.map +1 -1
- package/dist/commands/offer.js +376 -26
- package/dist/commands/offer.js.map +1 -1
- package/dist/commands/order-list.js +29 -0
- package/dist/commands/order-list.js.map +1 -1
- package/dist/commands/order-logistics.js +10 -0
- package/dist/commands/order-logistics.js.map +1 -1
- package/dist/commands/search.js +212 -51
- package/dist/commands/search.js.map +1 -1
- package/dist/commands/seller-messages.js +515 -16
- package/dist/commands/seller-messages.js.map +1 -1
- package/dist/commands/similar.js +123 -0
- package/dist/commands/similar.js.map +1 -0
- package/dist/daemon/client.js +10 -5
- package/dist/daemon/client.js.map +1 -1
- package/dist/daemon/manager.js +3 -1
- package/dist/daemon/manager.js.map +1 -1
- package/dist/daemon/server.js +15 -10
- package/dist/daemon/server.js.map +1 -1
- package/dist/session/dispatch.js +1 -0
- package/dist/session/dispatch.js.map +1 -1
- package/dist/session/paths.js +5 -0
- package/dist/session/paths.js.map +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cart-remove.js","sourceRoot":"","sources":["../../src/commands/cart-remove.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AAClD,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAC3C,OAAO,EACL,OAAO,IAAI,eAAe,GAE3B,MAAM,gBAAgB,CAAC;AAiBxB,MAAM,CAAC,KAAK,UAAU,OAAO,CAC3B,GAAmB,EACnB,IAAoB;IAEpB,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC;QAC/B,MAAM,IAAI,QAAQ,CAAC,CAAC,EAAE,WAAW,EAAE,mBAAmB,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC;IACvE,CAAC;IAED,iDAAiD;IACjD,IAAI,CAAC,yBAAyB,CAAC,CAAC;IAChC,MAAM,MAAM,GAAG,MAAM,eAAe,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;IAC9C,MAAM,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,IAAI,CAAC,MAAM,CAAC,CAAC;IAClE,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,MAAM,IAAI,QAAQ,CAChB,EAAE,EACF,qBAAqB,EACrB,aAAa,IAAI,CAAC,MAAM,0DAA0D,CACnF,CAAC;IACJ,CAAC;IAED,yEAAyE;IACzE,IAAI,CAAC,aAAa,MAAM,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,CAAC;IAC1D,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,OAAO,EAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"cart-remove.js","sourceRoot":"","sources":["../../src/commands/cart-remove.ts"],"names":[],"mappings":"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"}
|
|
@@ -4,7 +4,7 @@ import os from 'node:os';
|
|
|
4
4
|
import { dispatch } from '../session/dispatch.js';
|
|
5
5
|
import { emit, info } from '../io/output.js';
|
|
6
6
|
import { CliError } from '../io/errors.js';
|
|
7
|
-
import {
|
|
7
|
+
import { SEARCH_MTOP_API, SEARCH_APP_ID, parseMtopJsonp, mapOffer, } from './search.js';
|
|
8
8
|
const UPLOAD_PAGE = 'https://s.1688.com/youyuan/index.htm';
|
|
9
9
|
const RESULT_URL = (imageId) => `https://s.1688.com/selloffer/offer_search.htm?imageId=${imageId}`;
|
|
10
10
|
export async function execute(ctx, args) {
|
|
@@ -87,22 +87,55 @@ async function uploadAndGetImageId(ctx, imagePath) {
|
|
|
87
87
|
}
|
|
88
88
|
async function searchByImageId(ctx, imageId) {
|
|
89
89
|
const page = await ctx.newPage();
|
|
90
|
+
// Same mtop interception pattern as text `search` — image-search and
|
|
91
|
+
// keyword-search share the WirelessRecommend.recommend endpoint (appId=32517).
|
|
92
|
+
let captured = [];
|
|
93
|
+
const onResp = async (resp) => {
|
|
94
|
+
const u = resp.url();
|
|
95
|
+
if (!u.includes(SEARCH_MTOP_API))
|
|
96
|
+
return;
|
|
97
|
+
try {
|
|
98
|
+
const dataParam = new URLSearchParams(new URL(u).search).get('data') ?? '';
|
|
99
|
+
const dataObj = JSON.parse(dataParam);
|
|
100
|
+
if (String(dataObj.appId) !== SEARCH_APP_ID)
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
catch {
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
try {
|
|
107
|
+
const body = await resp.text();
|
|
108
|
+
const json = parseMtopJsonp(body);
|
|
109
|
+
const items = json?.data?.data?.OFFER?.items ?? [];
|
|
110
|
+
const offers = items
|
|
111
|
+
.map(mapOffer)
|
|
112
|
+
.filter((o) => o !== null);
|
|
113
|
+
if (offers.length > captured.length)
|
|
114
|
+
captured = offers;
|
|
115
|
+
}
|
|
116
|
+
catch {
|
|
117
|
+
/* malformed — skip */
|
|
118
|
+
}
|
|
119
|
+
};
|
|
120
|
+
page.on('response', onResp);
|
|
90
121
|
try {
|
|
91
122
|
await page.goto(RESULT_URL(imageId), {
|
|
92
123
|
waitUntil: 'domcontentloaded',
|
|
93
124
|
timeout: 30000,
|
|
94
125
|
});
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
126
|
+
const deadline = Date.now() + 15000;
|
|
127
|
+
while (Date.now() < deadline) {
|
|
128
|
+
if (page.isClosed()) {
|
|
129
|
+
throw new CliError(130, 'CANCELED', 'Browser closed.');
|
|
130
|
+
}
|
|
131
|
+
if (captured.length > 0)
|
|
132
|
+
break;
|
|
133
|
+
if (/\/punish|x5secdata=/.test(page.url()))
|
|
134
|
+
break;
|
|
135
|
+
await new Promise((r) => setTimeout(r, 300));
|
|
100
136
|
}
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
await page.evaluate(() => window.scrollBy(0, 2000));
|
|
104
|
-
await new Promise((r) => setTimeout(r, 1500));
|
|
105
|
-
return await extractOffers(page);
|
|
137
|
+
page.off('response', onResp);
|
|
138
|
+
return captured;
|
|
106
139
|
}
|
|
107
140
|
finally {
|
|
108
141
|
await page.close().catch(() => { });
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"image-search.js","sourceRoot":"","sources":["../../src/commands/image-search.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAClC,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,MAAM,SAAS,CAAC;AAEzB,OAAO,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AAClD,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAC3C,OAAO,
|
|
1
|
+
{"version":3,"file":"image-search.js","sourceRoot":"","sources":["../../src/commands/image-search.ts"],"names":[],"mappings":"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"}
|
package/dist/commands/offer.js
CHANGED
|
@@ -2,6 +2,7 @@ import { dispatch } from '../session/dispatch.js';
|
|
|
2
2
|
import { emit, info } from '../io/output.js';
|
|
3
3
|
import { CliError } from '../io/errors.js';
|
|
4
4
|
const SKU_API_RE = /wosc\.queryofferskuselectormodel/i;
|
|
5
|
+
let DETAIL_SEQ = 0;
|
|
5
6
|
export async function execute(ctx, args) {
|
|
6
7
|
if (!/^\d+$/.test(args.offerId)) {
|
|
7
8
|
throw new CliError(2, 'BAD_INPUT', `Invalid offerId: ${args.offerId}`);
|
|
@@ -12,19 +13,127 @@ export async function execute(ctx, args) {
|
|
|
12
13
|
resolveSku = r;
|
|
13
14
|
});
|
|
14
15
|
const onResp = async (resp) => {
|
|
15
|
-
if (
|
|
16
|
+
if (SKU_API_RE.test(resp.url())) {
|
|
17
|
+
try {
|
|
18
|
+
const text = await resp.text();
|
|
19
|
+
if (process.env.BB1688_PROBE === '1') {
|
|
20
|
+
try {
|
|
21
|
+
const fs = await import('node:fs/promises');
|
|
22
|
+
await fs.writeFile('/tmp/1688-sku-raw.json', text);
|
|
23
|
+
process.stderr.write(`[probe] saved sku → /tmp/1688-sku-raw.json (${text.length} bytes)\n`);
|
|
24
|
+
}
|
|
25
|
+
catch {
|
|
26
|
+
/* ignore */
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
const json = parseMtop(text);
|
|
30
|
+
if (json?.data?.skuSelectorBizModel)
|
|
31
|
+
resolveSku(json.data.skuSelectorBizModel);
|
|
32
|
+
}
|
|
33
|
+
catch {
|
|
34
|
+
/* ignore */
|
|
35
|
+
}
|
|
16
36
|
return;
|
|
17
|
-
try {
|
|
18
|
-
const text = await resp.text();
|
|
19
|
-
const json = parseMtop(text);
|
|
20
|
-
if (json?.data?.skuSelectorBizModel)
|
|
21
|
-
resolveSku(json.data.skuSelectorBizModel);
|
|
22
37
|
}
|
|
23
|
-
|
|
24
|
-
|
|
38
|
+
// Probe: save every offerdetail.service response so we can see which
|
|
39
|
+
// call carries productAttributes.
|
|
40
|
+
if (process.env.BB1688_PROBE === '1' &&
|
|
41
|
+
/mmga\.offerdetail\.service/i.test(resp.url())) {
|
|
42
|
+
try {
|
|
43
|
+
const text = await resp.text();
|
|
44
|
+
const fs = await import('node:fs/promises');
|
|
45
|
+
DETAIL_SEQ++;
|
|
46
|
+
const file = `/tmp/1688-offerdetail-${String(DETAIL_SEQ).padStart(2, '0')}.json`;
|
|
47
|
+
await fs.writeFile(file, text);
|
|
48
|
+
process.stderr.write(`[probe] saved offerdetail → ${file} (${text.length} bytes)\n`);
|
|
49
|
+
}
|
|
50
|
+
catch {
|
|
51
|
+
/* ignore */
|
|
52
|
+
}
|
|
25
53
|
}
|
|
26
54
|
};
|
|
27
55
|
page.on('response', onResp);
|
|
56
|
+
if (process.env.BB1688_PROBE === '1') {
|
|
57
|
+
const log = (line) => process.stderr.write(line + '\n');
|
|
58
|
+
log('[probe] active (offer)');
|
|
59
|
+
let mtopSeq = 0;
|
|
60
|
+
let htmlSeq = 0;
|
|
61
|
+
page.on('response', async (resp) => {
|
|
62
|
+
const u = resp.url();
|
|
63
|
+
const ct = resp.headers()['content-type'] ?? '';
|
|
64
|
+
if (/\.(png|jpg|jpeg|gif|webp|css|woff2?|svg|ico|mp4|ttf|otf|js|map)(\?|$)/i.test(u))
|
|
65
|
+
return;
|
|
66
|
+
if (/mmstat\.com|google-analytics|alicdn\.com\/sufei/.test(u))
|
|
67
|
+
return;
|
|
68
|
+
try {
|
|
69
|
+
const path = new URL(u).pathname;
|
|
70
|
+
// mtop OR any non-mtop XHR-style endpoint (wosc.*, *.json, etc.)
|
|
71
|
+
const isApi = /mtop[.\/]|wosc\.|h5api|\/api\/|\/ajax\/|\.json/i.test(path) ||
|
|
72
|
+
/json/i.test(ct);
|
|
73
|
+
if (isApi) {
|
|
74
|
+
let body = '';
|
|
75
|
+
try {
|
|
76
|
+
body = await resp.text();
|
|
77
|
+
}
|
|
78
|
+
catch {
|
|
79
|
+
/* ignore */
|
|
80
|
+
}
|
|
81
|
+
const offerHits = (body.match(/"offerId|offerId":/g) ?? []).length;
|
|
82
|
+
const titleHits = (body.match(/"subject"|"title"/g) ?? []).length;
|
|
83
|
+
const priceHits = (body.match(/"price"|priceInfo|priceRange/g) ?? [])
|
|
84
|
+
.length;
|
|
85
|
+
log(`[api ] ${path.slice(0, 80)} ct=${ct.slice(0, 25)} bodyLen=${body.length} offerId×${offerHits} title×${titleHits} price×${priceHits}`);
|
|
86
|
+
if (body.length > 3000 && (offerHits > 0 || titleHits > 0)) {
|
|
87
|
+
try {
|
|
88
|
+
const fs = await import('node:fs/promises');
|
|
89
|
+
const seq = (++mtopSeq).toString().padStart(2, '0');
|
|
90
|
+
const tag = path.split('/').filter(Boolean).pop() ?? 'api';
|
|
91
|
+
const file = `/tmp/1688-offer-mtop-${seq}-${tag.slice(0, 40)}.json`;
|
|
92
|
+
await fs.writeFile(file, body);
|
|
93
|
+
log(`[api ] saved → ${file}`);
|
|
94
|
+
}
|
|
95
|
+
catch {
|
|
96
|
+
/* ignore */
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
// HTML responses on detail.1688.com — likely SSR shell with inline data
|
|
102
|
+
if (/detail\.1688\.com|detail\.m\.1688\.com/.test(u) &&
|
|
103
|
+
/text\/html/i.test(ct)) {
|
|
104
|
+
const body = await resp.text();
|
|
105
|
+
try {
|
|
106
|
+
const fs = await import('node:fs/promises');
|
|
107
|
+
const seq = (++htmlSeq).toString().padStart(2, '0');
|
|
108
|
+
const file = `/tmp/1688-offer-page-${seq}.html`;
|
|
109
|
+
await fs.writeFile(file, body);
|
|
110
|
+
// Probe for known inline-JSON variables.
|
|
111
|
+
const markers = [
|
|
112
|
+
'window.runParams',
|
|
113
|
+
'window.detailData',
|
|
114
|
+
'window.context',
|
|
115
|
+
'window.offerDetail',
|
|
116
|
+
'window.__INITIAL_DATA__',
|
|
117
|
+
'window.__detail__',
|
|
118
|
+
'window.__VITA_DATA__',
|
|
119
|
+
'window.dataLayer',
|
|
120
|
+
'"offerId":',
|
|
121
|
+
'"subject":',
|
|
122
|
+
'"sellerLoginId":',
|
|
123
|
+
];
|
|
124
|
+
const hits = markers.filter((k) => body.includes(k));
|
|
125
|
+
log(`[html] saved → ${file} (${body.length} bytes) markers=[${hits.join(', ')}]`);
|
|
126
|
+
}
|
|
127
|
+
catch {
|
|
128
|
+
/* ignore */
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
catch {
|
|
133
|
+
/* ignore */
|
|
134
|
+
}
|
|
135
|
+
});
|
|
136
|
+
}
|
|
28
137
|
const url = `https://detail.1688.com/offer/${args.offerId}.html`;
|
|
29
138
|
info(`Fetching offer ${args.offerId}...`);
|
|
30
139
|
try {
|
|
@@ -41,15 +150,183 @@ export async function execute(ctx, args) {
|
|
|
41
150
|
new Promise((res) => setTimeout(() => res(null), 18000)),
|
|
42
151
|
]));
|
|
43
152
|
page.off('response', onResp);
|
|
44
|
-
const
|
|
45
|
-
return assemble(args.offerId, url, sku,
|
|
153
|
+
const pageInfo = await readPageInfo(page);
|
|
154
|
+
return assemble(args.offerId, url, sku, pageInfo);
|
|
46
155
|
}
|
|
47
156
|
function parseMtop(text) {
|
|
48
157
|
const t = text.trim();
|
|
49
158
|
const m = t.match(/^\s*mtopjsonp\d+\(([\s\S]*)\)\s*$/);
|
|
50
159
|
return JSON.parse(m ? m[1] : t);
|
|
51
160
|
}
|
|
52
|
-
|
|
161
|
+
/**
|
|
162
|
+
* Extract product info from the inline `window.context.result.data` JS
|
|
163
|
+
* object that 1688 ships in the SSR HTML response. Bypasses fragile DOM
|
|
164
|
+
* selectors by letting Playwright serialize the parsed JS object back to
|
|
165
|
+
* Node over the wire.
|
|
166
|
+
*
|
|
167
|
+
* Falls back to DOM scraping if the inline data isn't available for some
|
|
168
|
+
* reason (e.g. server rendered a fallback view).
|
|
169
|
+
*/
|
|
170
|
+
async function readPageInfo(page) {
|
|
171
|
+
const debug = process.env.BB1688_DEBUG === '1';
|
|
172
|
+
if (debug) {
|
|
173
|
+
page.on('console', (msg) => {
|
|
174
|
+
const t = msg.text();
|
|
175
|
+
if (t.includes('[bb1688-probe]') || t.includes('[bb1688]'))
|
|
176
|
+
process.stderr.write(t + '\n');
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
try {
|
|
180
|
+
await page.waitForFunction(() => {
|
|
181
|
+
const w = window;
|
|
182
|
+
return !!w.context?.result?.data?.productTitle?.fields;
|
|
183
|
+
}, { timeout: 8000 });
|
|
184
|
+
}
|
|
185
|
+
catch {
|
|
186
|
+
return scrapeDomFallback(page);
|
|
187
|
+
}
|
|
188
|
+
// Modest scroll to trigger lazy modules near the SKU + 参数 section.
|
|
189
|
+
// Avoid scrolling to bottom — 1688 detail pages infinite-scroll related
|
|
190
|
+
// products there, which can hang the renderer.
|
|
191
|
+
try {
|
|
192
|
+
await page.evaluate(() => window.scrollTo(0, 1500));
|
|
193
|
+
await new Promise((r) => setTimeout(r, 1000));
|
|
194
|
+
await page.evaluate(() => window.scrollTo(0, 3000));
|
|
195
|
+
await new Promise((r) => setTimeout(r, 1000));
|
|
196
|
+
}
|
|
197
|
+
catch {
|
|
198
|
+
/* best-effort */
|
|
199
|
+
}
|
|
200
|
+
const fromContext = await page
|
|
201
|
+
.evaluate((debugMode) => {
|
|
202
|
+
const w = window;
|
|
203
|
+
const d = w.context?.result?.data;
|
|
204
|
+
if (!d)
|
|
205
|
+
return null;
|
|
206
|
+
const feg = w.FE_GLOBALS ?? {};
|
|
207
|
+
// description module — has detailUrl + leafCategoryId.
|
|
208
|
+
const descFields = d.description?.fields ?? {};
|
|
209
|
+
// Product attributes live in a deeply-nested branch (1688 typically
|
|
210
|
+
// serializes them under `globalData.model.offerDetail.featureAttributes`,
|
|
211
|
+
// but the wrapping path varies). Walk the entire window.context tree
|
|
212
|
+
// (bounded depth) looking for the canonical featureAttributes array.
|
|
213
|
+
const attributes = [];
|
|
214
|
+
const root = (w.context ?? d);
|
|
215
|
+
const stack = [{ v: root, depth: 0 }];
|
|
216
|
+
while (stack.length && attributes.length === 0) {
|
|
217
|
+
const { v, depth } = stack.shift();
|
|
218
|
+
if (depth > 12)
|
|
219
|
+
continue;
|
|
220
|
+
if (!v || typeof v !== 'object')
|
|
221
|
+
continue;
|
|
222
|
+
if (Array.isArray(v)) {
|
|
223
|
+
// Detect attribute-list array shape.
|
|
224
|
+
if (v.length > 0 && typeof v[0] === 'object' && v[0] !== null) {
|
|
225
|
+
const first = v[0];
|
|
226
|
+
if (typeof first.name === 'string' &&
|
|
227
|
+
('value' in first || 'values' in first)) {
|
|
228
|
+
for (const item of v) {
|
|
229
|
+
if (!item || typeof item !== 'object')
|
|
230
|
+
continue;
|
|
231
|
+
const it = item;
|
|
232
|
+
const name = typeof it.name === 'string' ? it.name.trim() : '';
|
|
233
|
+
let value = '';
|
|
234
|
+
if (typeof it.value === 'string')
|
|
235
|
+
value = it.value;
|
|
236
|
+
else if (Array.isArray(it.values))
|
|
237
|
+
value = it.values
|
|
238
|
+
.filter((x) => typeof x === 'string')
|
|
239
|
+
.join(',');
|
|
240
|
+
if (name && value)
|
|
241
|
+
attributes.push({ name, value });
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
for (const item of v)
|
|
246
|
+
stack.push({ v: item, depth: depth + 1 });
|
|
247
|
+
}
|
|
248
|
+
else {
|
|
249
|
+
// Prioritize keys that hint at attribute containers.
|
|
250
|
+
const obj = v;
|
|
251
|
+
// Direct hit
|
|
252
|
+
const direct = obj.featureAttributes ?? obj.productAttributes ?? obj.attributes;
|
|
253
|
+
if (Array.isArray(direct))
|
|
254
|
+
stack.unshift({ v: direct, depth: depth + 1 });
|
|
255
|
+
for (const k of Object.keys(obj))
|
|
256
|
+
stack.push({ v: obj[k], depth: depth + 1 });
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
// Package info — per-SKU dimensions/weight (件重尺).
|
|
260
|
+
const packRaw = d.productPackInfo?.fields?.pieceWeightScale?.pieceWeightScaleInfo;
|
|
261
|
+
const packageInfo = [];
|
|
262
|
+
if (Array.isArray(packRaw)) {
|
|
263
|
+
for (const p of packRaw) {
|
|
264
|
+
if (!p || typeof p !== 'object')
|
|
265
|
+
continue;
|
|
266
|
+
const o = p;
|
|
267
|
+
packageInfo.push({
|
|
268
|
+
skuId: o.skuId != null ? String(o.skuId) : '',
|
|
269
|
+
spec: o.sku1 ?? '',
|
|
270
|
+
length: o.length ?? null,
|
|
271
|
+
width: o.width ?? null,
|
|
272
|
+
height: o.height ?? null,
|
|
273
|
+
weight: o.weight ?? null,
|
|
274
|
+
volume: o.volume ?? null,
|
|
275
|
+
});
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
// Page is organized by widget modules; real data lives in `<mod>.fields`.
|
|
279
|
+
const productTitle = d.productTitle?.fields ?? {};
|
|
280
|
+
const gallery = d.gallery?.fields ?? {};
|
|
281
|
+
const shop = productTitle.shopInfo ?? {};
|
|
282
|
+
const imgs = [];
|
|
283
|
+
const rawImgs = gallery.mainImage;
|
|
284
|
+
if (Array.isArray(rawImgs)) {
|
|
285
|
+
for (const img of rawImgs) {
|
|
286
|
+
if (typeof img === 'string')
|
|
287
|
+
imgs.push(img);
|
|
288
|
+
else if (img && typeof img === 'object') {
|
|
289
|
+
const o = img;
|
|
290
|
+
const url = o.fullPathImageURI ?? o.size310x310ImageURI ?? o.imageURI ?? '';
|
|
291
|
+
if (url) {
|
|
292
|
+
imgs.push(url.startsWith('http') ? url : `https://cbu01.alicdn.com/${url}`);
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
const catId = descFields.leafCategoryId != null
|
|
298
|
+
? String(descFields.leafCategoryId)
|
|
299
|
+
: null;
|
|
300
|
+
return {
|
|
301
|
+
detailUrl: descFields.detailUrl ?? null,
|
|
302
|
+
attributes,
|
|
303
|
+
packageInfo,
|
|
304
|
+
title: productTitle.title ?? gallery.subject ?? '',
|
|
305
|
+
supplierName: shop.companyName ?? shop.authCompanyName ?? null,
|
|
306
|
+
sellerLoginId: feg.offerLoginId ?? feg.loginId ?? null,
|
|
307
|
+
sellerMemberId: feg.memberId ?? null,
|
|
308
|
+
sellerUserId: null,
|
|
309
|
+
saledCount: null,
|
|
310
|
+
mainImage: imgs[0] ?? null,
|
|
311
|
+
images: imgs,
|
|
312
|
+
sendArea: null,
|
|
313
|
+
province: null,
|
|
314
|
+
city: null,
|
|
315
|
+
categoryId: catId,
|
|
316
|
+
};
|
|
317
|
+
}, debug)
|
|
318
|
+
.catch(() => null);
|
|
319
|
+
if (!fromContext)
|
|
320
|
+
return scrapeDomFallback(page);
|
|
321
|
+
// Title from <title> as backup when subject empty.
|
|
322
|
+
let title = fromContext.title;
|
|
323
|
+
if (!title) {
|
|
324
|
+
const raw = await page.title();
|
|
325
|
+
title = raw.replace(/\s*-\s*阿里巴巴\s*$/, '').trim();
|
|
326
|
+
}
|
|
327
|
+
return { ...fromContext, title };
|
|
328
|
+
}
|
|
329
|
+
async function scrapeDomFallback(page) {
|
|
53
330
|
const raw = await page.title();
|
|
54
331
|
const title = raw.replace(/\s*-\s*阿里巴巴\s*$/, '').trim();
|
|
55
332
|
const info = await page.evaluate(() => {
|
|
@@ -63,16 +340,30 @@ async function scrapeDom(page) {
|
|
|
63
340
|
}
|
|
64
341
|
return {
|
|
65
342
|
supplierName: txt('h1') ?? null,
|
|
66
|
-
// Try common image carousel selectors
|
|
67
343
|
mainImage: imgSrc('.v-image-wrap img') ??
|
|
68
344
|
imgSrc('.ant-image-img') ??
|
|
69
345
|
imgSrc('img[alt*="主图"]'),
|
|
70
|
-
sendArea: null,
|
|
71
346
|
};
|
|
72
347
|
});
|
|
73
|
-
return {
|
|
348
|
+
return {
|
|
349
|
+
title,
|
|
350
|
+
supplierName: info.supplierName,
|
|
351
|
+
sellerLoginId: null,
|
|
352
|
+
sellerMemberId: null,
|
|
353
|
+
sellerUserId: null,
|
|
354
|
+
saledCount: null,
|
|
355
|
+
mainImage: info.mainImage,
|
|
356
|
+
images: info.mainImage ? [info.mainImage] : [],
|
|
357
|
+
sendArea: null,
|
|
358
|
+
province: null,
|
|
359
|
+
city: null,
|
|
360
|
+
categoryId: null,
|
|
361
|
+
detailUrl: null,
|
|
362
|
+
attributes: [],
|
|
363
|
+
packageInfo: [],
|
|
364
|
+
};
|
|
74
365
|
}
|
|
75
|
-
function assemble(offerId, url, sku,
|
|
366
|
+
function assemble(offerId, url, sku, info) {
|
|
76
367
|
const priceRange = sku?.skuPriceScale ?? null;
|
|
77
368
|
const { min: priceMin, max: priceMax } = parseRange(priceRange);
|
|
78
369
|
const options = (sku?.skuProps ?? []).map((p) => ({
|
|
@@ -82,31 +373,90 @@ function assemble(offerId, url, sku, dom) {
|
|
|
82
373
|
imageUrl: v.imageUrl ?? null,
|
|
83
374
|
})),
|
|
84
375
|
}));
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
376
|
+
// Build a map: option value name → image (e.g. "22管径长方头" → cbu URL).
|
|
377
|
+
// Used to derive a per-SKU image since the SKU itself doesn't carry one.
|
|
378
|
+
const valueImage = new Map();
|
|
379
|
+
for (const opt of options) {
|
|
380
|
+
for (const v of opt.values) {
|
|
381
|
+
if (v.imageUrl)
|
|
382
|
+
valueImage.set(v.name, v.imageUrl);
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
// SKU specs is HTML-encoded (">" = ">"). Split by either, take first part.
|
|
386
|
+
// Falls back to the offer's main image when the seller didn't upload
|
|
387
|
+
// per-spec thumbnails — keeps every SKU with a usable preview URL.
|
|
388
|
+
const fallbackSkuImage = info.mainImage ?? options[0]?.values[0]?.imageUrl ?? null;
|
|
389
|
+
function deriveSkuImage(spec) {
|
|
390
|
+
const firstPart = spec.split(/>|>/)[0]?.trim() ?? '';
|
|
391
|
+
return valueImage.get(firstPart) ?? fallbackSkuImage;
|
|
392
|
+
}
|
|
393
|
+
const skus = Object.entries(sku?.skuInfoMap ?? {}).map(([k, v]) => {
|
|
394
|
+
const specs = v.specAttrs ?? k;
|
|
395
|
+
return {
|
|
396
|
+
skuId: v.skuId ?? '',
|
|
397
|
+
specs,
|
|
398
|
+
price: parseFloatOrNull(v.discountPrice ?? v.price),
|
|
399
|
+
multiPrice: parseFloatOrNull(v.multiPrice),
|
|
400
|
+
stock: parseIntOrNull(v.canBookCount),
|
|
401
|
+
saleCount: typeof v.saleCount === 'number'
|
|
402
|
+
? v.saleCount
|
|
403
|
+
: parseIntOrNull(v.saleCount) ?? 0,
|
|
404
|
+
image: deriveSkuImage(specs),
|
|
405
|
+
};
|
|
406
|
+
});
|
|
91
407
|
const freight = {
|
|
92
408
|
receiveAddress: sku?.extraInfo?.freightInfo?.receiveAddress ?? null,
|
|
93
|
-
sendArea:
|
|
409
|
+
sendArea: info.sendArea,
|
|
410
|
+
province: info.province,
|
|
411
|
+
city: info.city,
|
|
94
412
|
unitWeight: sku?.extraInfo?.freightInfo?.unitWeight ?? null,
|
|
95
413
|
};
|
|
96
|
-
const fallbackImage = options[0]?.values[0]?.imageUrl ??
|
|
414
|
+
const fallbackImage = info.mainImage ?? options[0]?.values[0]?.imageUrl ?? null;
|
|
415
|
+
const trade = sku?.skuSelectorModel?.tradeModel;
|
|
416
|
+
const priceTiers = (trade?.offerPriceModel?.currentPrices ?? [])
|
|
417
|
+
.map((t) => ({
|
|
418
|
+
minQty: parseIntOrNull(String(t.beginAmount ?? '')) ?? 0,
|
|
419
|
+
price: parseFloatOrNull(String(t.price ?? '')) ?? 0,
|
|
420
|
+
}))
|
|
421
|
+
.filter((t) => t.minQty > 0 && t.price > 0);
|
|
422
|
+
const tradeSaleCount = typeof trade?.saleCount === 'number'
|
|
423
|
+
? trade.saleCount
|
|
424
|
+
: parseIntOrNull(trade?.saleCount);
|
|
97
425
|
return {
|
|
98
426
|
offerId,
|
|
99
|
-
title:
|
|
427
|
+
title: info.title,
|
|
100
428
|
url,
|
|
101
429
|
priceRange,
|
|
102
430
|
priceMin,
|
|
103
431
|
priceMax,
|
|
104
|
-
unitName: null,
|
|
105
|
-
|
|
432
|
+
unitName: trade?.unit ?? null,
|
|
433
|
+
minOrderQty: parseIntOrNull(String(trade?.beginAmount ?? '')),
|
|
434
|
+
mixOrderQty: parseIntOrNull(String(trade?.mixModel?.mixAmount ?? '')),
|
|
435
|
+
priceTiers,
|
|
436
|
+
detailUrl: info.detailUrl,
|
|
437
|
+
attributes: info.attributes,
|
|
438
|
+
packageInfo: info.packageInfo,
|
|
439
|
+
supplier: {
|
|
440
|
+
name: info.supplierName,
|
|
441
|
+
loginId: info.sellerLoginId,
|
|
442
|
+
memberId: info.sellerMemberId,
|
|
443
|
+
// sellerUserId is exposed via SKU mtop freightInfo; window.context omits it.
|
|
444
|
+
userId: info.sellerUserId ??
|
|
445
|
+
(sku?.extraInfo?.freightInfo?.sellerUserId != null
|
|
446
|
+
? String(sku.extraInfo.freightInfo.sellerUserId)
|
|
447
|
+
: null),
|
|
448
|
+
},
|
|
106
449
|
freight,
|
|
450
|
+
saledCount: tradeSaleCount ??
|
|
451
|
+
info.saledCount ??
|
|
452
|
+
(skus.length > 0
|
|
453
|
+
? skus.reduce((s, x) => s + (x.saleCount || 0), 0)
|
|
454
|
+
: null),
|
|
455
|
+
categoryId: info.categoryId,
|
|
107
456
|
options,
|
|
108
457
|
skus,
|
|
109
458
|
mainImage: fallbackImage,
|
|
459
|
+
images: info.images,
|
|
110
460
|
};
|
|
111
461
|
}
|
|
112
462
|
function parseRange(s) {
|