@cloud411716/fancy-webnovel 0.2.9 → 0.2.11

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cloud411716/fancy-webnovel",
3
- "version": "0.2.9",
3
+ "version": "0.2.11",
4
4
  "type": "module",
5
5
  "main": "index.js",
6
6
  "exports": {
@@ -249,6 +249,7 @@ function cleanDesc(raw) {
249
249
  // ---------------------------------------------------------------------------
250
250
 
251
251
  const args = process.argv.slice(2);
252
+ const PROBE = getArg(args, "--probe") !== null;
252
253
  const LOGIN_WAIT = parseInt(getArg(args, "--login-wait") || "0", 10);
253
254
  const OUTDIR = getArg(args, "--outdir") || ".";
254
255
  const CHANNEL = getArg(args, "--channel") || "1";
@@ -306,6 +307,69 @@ async function scrapeChannel(ch, type) {
306
307
  console.log(` ⚠ 页面未挂载 __INITIAL_STATE__,将尝试兜底扫描,结果可能不完整。`);
307
308
  }
308
309
 
310
+ // ─── 调试模式:拦截所有请求,找出真实数据接口 ───
311
+ if (PROBE) {
312
+ const intercepted = [];
313
+ const seen = new Set();
314
+
315
+ // 先注册拦截器,再导航到目标页(避免漏掉 initial 请求)
316
+ context.on("request", req => {
317
+ const url = req.url();
318
+ if (seen.has(url)) return;
319
+ if (/\.(css|woff|jpg|png|ico)/.test(url)) return;
320
+ if (!url.includes("fanqie")) return;
321
+ seen.add(url);
322
+ console.log(`[REQ] ${url}`);
323
+ });
324
+
325
+ page.on("response", async (resp) => {
326
+ const url = resp.url();
327
+ const ct = (resp.headers()["content-type"] || "").toLowerCase();
328
+ if (seen.has(url)) return;
329
+ if (!ct.includes("json") && !ct.includes("text") && !url.includes("api")) return;
330
+ if (/\.(css|woff|jpg|png|ico)/.test(url)) return;
331
+ try {
332
+ const body = await resp.text();
333
+ if (!body || body.length < 50) return;
334
+ let parsed;
335
+ try { parsed = JSON.parse(body); } catch { return; }
336
+ const str = JSON.stringify(parsed);
337
+ if (str.includes("bookId") || str.includes("book_name") || str.includes("bookName") || str.includes("authorName")) {
338
+ console.log(`[JSON] ${url}`);
339
+ console.log(` 预览: ${str.slice(0, 300)}`);
340
+ intercepted.push({ url, preview: str.slice(0, 400) });
341
+ }
342
+ } catch {}
343
+ });
344
+
345
+ // 直接导航到品类页(不用 waitUntil,避免卡住)
346
+ const cats = await extractCategories(page, ch, type);
347
+ if (!cats.length) {
348
+ await page.goto(`https://fanqienovel.com/rank/${ch}_${type}_${initCatId}`);
349
+ await page.waitForTimeout(3000);
350
+ const moreCats = await extractCategories(page, ch, type);
351
+ if (moreCats.length) {
352
+ console.log(` 发现 ${moreCats.length} 个品类`);
353
+ for (const c of moreCats.slice(0, 3)) {
354
+ console.log(` 探测品类: ${c.name} → ${c.href}`);
355
+ await page.goto(`https://fanqienovel.com${c.href}`);
356
+ await page.waitForTimeout(2000);
357
+ }
358
+ }
359
+ } else {
360
+ console.log(` 发现 ${cats.length} 个品类`);
361
+ for (const c of cats.slice(0, 3)) {
362
+ console.log(` 探测品类: ${c.name} → ${c.href}`);
363
+ await page.goto(`https://fanqienovel.com${c.href}`);
364
+ await page.waitForTimeout(2000);
365
+ }
366
+ }
367
+
368
+ console.log(`\n=== 共拦截到 ${intercepted.length} 个含书籍数据的接口 ===`);
369
+ await browser.close();
370
+ return null;
371
+ }
372
+
309
373
  // 提取品类菜单
310
374
  let categories = await extractCategories(page, ch, type);
311
375
  if (!categories.length) {