@cloud411716/fancy-webnovel 0.2.11 → 0.2.13

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.11",
3
+ "version": "0.2.13",
4
4
  "type": "module",
5
5
  "main": "index.js",
6
6
  "exports": {
@@ -3,110 +3,99 @@
3
3
 
4
4
  ---
5
5
 
6
- ## 起点
6
+ ## 字段规范(所有平台通用)
7
7
 
8
- ### 起点采集说明
8
+ 每本书单独输出以下四个字段,不得合并为一行:
9
9
 
10
- 榜单清单与 URL 见 SKILL.md「起点采集目标」表。
10
+ ```
11
+ 书名:{书名}
12
+ 题材:{题材}
13
+ 作者:{作者}
14
+ 作品页:{URL}
15
+ ```
11
16
 
12
- 优先使用 `scripts/qidian-rank-scraper.js` 的默认 `--mode auto`。脚本先读取 `https://m.qidian.com` 移动端 SSR pageContext JSON,规避 PC 站风控页;移动端不可用时才回退到 CDP/PC 页面。输出头部会标注 `抓取方式:mobile-ssr` 或 `cdp-pc`。
17
+ ---
13
18
 
19
+ ## 番茄小说
14
20
 
15
- ### 字段
21
+ ### 题材 cat_id
16
22
 
17
- 排名 | 书名 | 作者 | 题材 | 状态 | 签约 | 收费模式 | 字数(万字) | 总推荐 | 标签(详情页) | 最新更新(详情页) | 作品页链接 | 简介(详情页,截断100字)
23
+ 男频19个:西方奇幻(1141) / 东方仙侠(1140) / 科幻末世(8) / 都市日常(261) / 都市修真(124) / 都市高武(1014) / 历史古代(273) / 战神赘婿(27) / 都市种田(263) / 传统玄幻(258) / 历史脑洞(272) / 悬疑脑洞(539) / 都市脑洞(262) / 玄幻脑洞(257) / 悬疑灵异(751) / 抗战谍战(504) / 游戏体育(746) / 动漫衍生(718) / 男频衍生(1016)
24
+
25
+ 女频18个:古风世情(1139) / 科幻末世(8) / 游戏体育(746) / 女频衍生(1015) / 玄幻言情(248) / 种田(23) / 年代(79) / 现言脑洞(267) / 宫斗宅斗(246) / 悬疑脑洞(539) / 古言脑洞(253) / 快穿(24) / 青春甜宠(749) / 星光璀璨(745) / 女频悬疑(747) / 职场婚恋(750) / 豪门总裁(748) / 民国言情(1017)
18
26
 
19
27
  ### 输出模板
20
28
 
21
29
  ```markdown
22
- # qidian · {榜单名称}
23
- - 来源:{榜单URL}
30
+ # 番茄 · {频道}{榜单名} · 全 {N} 题材
31
+ - 频道参数:channel={0女频/1男频},type={1新书榜/2阅读榜}
24
32
  - 抓取时间:{ISO 8601}
25
33
  - 条目数:{N}
26
34
 
27
35
  ---
28
36
 
29
- ## #{排名} {书名}
30
- *{作者} · {题材} · {状态} · {签约} · {免费/VIP} · {字数}万字 · {推荐数}总推荐*
31
- **标签:** {标签}
32
- **最新更新:** {YYYY-MM-DD HH:MM:SS} · {章节标题}
37
+ ## {题材名称}
33
38
 
34
- [作品页]({URL})
39
+ 书名:{书名}
40
+ 题材:{题材}
41
+ 作者:{作者}
42
+ 作品页:{URL}
35
43
 
36
- **简介**
37
- {简介原文}
44
+ 书名:{书名}
45
+ 题材:{题材}
46
+ 作者:{作者}
47
+ 作品页:{URL}
38
48
  ```
39
49
 
40
- ### 采集要点
41
-
42
- 榜单页含:排名/书名/作者/题材/字数/推荐/签约/免费VIP。详情页需:标签/最新更新/简介。三江按周分组。
50
+ > 番茄字体反爬:详情页 HTML 里有明文 bookName/author,列表页 innerText 被自定义字体混淆需详情页解码。
43
51
 
44
52
  ---
45
53
 
46
- ## 番茄小说
47
-
48
- 榜单 URL 格式与参数说明见 SKILL.md「番茄采集目标」表。
49
-
50
- ### 题材cat_id
51
-
52
- 男频19个:西方奇幻(1141) / 东方仙侠(1140) / 科幻末世(8) / 都市日常(261) / 都市修真(124) / 都市高武(1014) / 历史古代(273) / 战神赘婿(27) / 都市种田(263) / 传统玄幻(258) / 历史脑洞(272) / 悬疑脑洞(539) / 都市脑洞(262) / 玄幻脑洞(257) / 悬疑灵异(751) / 抗战谍战(504) / 游戏体育(746) / 动漫衍生(718) / 男频衍生(1016)
53
-
54
- 女频18个:古风世情(1139) / 科幻末世(8) / 游戏体育(746) / 女频衍生(1015) / 玄幻言情(248) / 种田(23) / 年代(79) / 现言脑洞(267) / 宫斗宅斗(246) / 悬疑脑洞(539) / 古言脑洞(253) / 快穿(24) / 青春甜宠(749) / 星光璀璨(745) / 女频悬疑(747) / 职场婚恋(750) / 豪门总裁(748) / 民国言情(1017)
54
+ ## 晋江文学城
55
55
 
56
- ### 字段
56
+ ### 榜单 URL
57
57
 
58
- 排名 | 书名(需详情页解码) | 作者(需详情页解码) | 题材(详情页 categoryV2) | 状态 | 在读(核心指标) | 字数 | 标签(简介内【】) | 最新更新 | bookId | 作品页链接 | 简介(截断100字)
58
+ `jjwxc.net/topten.php?orderstr={榜单ID}&t={频道ID}`
59
59
 
60
- > 番茄 SSR 详情页**没有数字评分**,故不输出评分。题材取详情页 `categoryV2`(转义 JSON 的首个 `Name`,如「西方奇幻」);标签取简介开头的 `【tag+tag+...】`(如「种田、慢热、西幻」),是题材细分的真实信号。
60
+ | 榜单 | orderstr |
61
+ |------|----------|
62
+ | 收入金榜 | 12 |
63
+ | 月榜 | 7 |
64
+ | 季度榜 | 8 |
65
+ | 完结金榜 | 14 |
66
+ | 新手金榜 | 15 |
67
+ | 千字金榜 | 17 |
61
68
 
62
69
  ### 输出模板
63
70
 
64
71
  ```markdown
65
- # 番茄 · {频道}{榜单名} · 全 {N} 题材
66
- - 频道参数:channel={0女频/1男频},type={1新书榜/2阅读榜}
72
+ # 晋江 · {榜单名}
73
+ - 来源:{topten URL}
67
74
  - 抓取时间:{ISO 8601}
68
- - 标题解析:成功 {X} / 共 {Y}
69
- - 数据质量:[OK / 标题解析异常 / 无数据]
70
- - 每题材上限 ≈ {N}(cap≈20)
75
+ - 条目数:{N}
71
76
 
72
77
  ---
73
78
 
74
- ## {题材名称} — {N} 本
75
-
76
- ### #{排名} {书名}
77
- *{作者} · {题材} · {状态} · {在读数} 在读 · {字数}字*
78
- **标签:** {标签1、标签2}
79
- **最新更新:** {章节}
80
- **bookId:** {bookId}
79
+ 书名:{书名}
80
+ 题材:{频道名}
81
+ 作者:{作者}
82
+ 作品页:https://www.jjwxc.net/onebook.php?novelid={id}
81
83
 
82
- [作品页]({URL})
83
-
84
- **简介**
85
- {简介原文}
84
+ 书名:{书名}
85
+ 题材:{频道名}
86
+ 作者:{作者}
87
+ 作品页:https://www.jjwxc.net/onebook.php?novelid={id}
86
88
  ```
87
89
 
88
- > 标题/作者/题材/标签/简介均为可选字段:详情页拿到才输出。书名解码失败时书名显示 `(标题待解析)`,但 bookId 与作品页链接始终保留,便于人工回查。
89
-
90
- ### 采集要点
91
-
92
- 字体反爬:列表页 innerText 被自定义字体混淆,`scripts/fanqie-rank-scraper.js` 改从详情页 HTML(内嵌 JSON `bookName`/`author`/`abstract`/`categoryV2` + `<title>` + og:meta)多策略解码明文,规避字体反爬。流程:访问品类页 → 提取品类链接 → 逐品类取 `__INITIAL_STATE__` 列表 → 分批(每 5 本)请求详情页解码。单页上限约 20 本需滚动加载;`--top N` 可调每题材上限。
93
-
94
- **故障排查(书名全是 `bookId:xxx` / `(标题待解析)`)**:
95
- - 看文件头 `数据质量`:标 `[标题解析异常]` 说明详情页解码失败率高。
96
- - 多为详情页结构变动或被登录/验证页拦截。在已登录的 Chrome 里手动打开任一 `https://fanqienovel.com/page/{bookId}` 确认页面正常、非验证页。
97
- - 控制台若报 ` playwright-core 无法启动浏览器`,说明系统缺少 Chrome/Edge 或浏览器路径不对,用 `--login-wait` 等待手动登录后重试。
90
+ > 编码:详情页必须 `fetch+arrayBuffer+TextDecoder('gb18030')` 解码。
98
91
 
99
92
  ---
100
93
 
101
- ## 七猫
94
+ ## 七猫小说
102
95
 
103
96
  ### 榜单
104
97
 
105
- 入口:qimao.com/paihang,男生榜/女生榜tab切换。类型:大热榜(日/月) / 新书榜 / 完结榜 / 收藏榜 / 更新榜
106
-
107
- ### 字段
108
-
109
- 排名 | 书名 | 作者 | 题材 | 分类标签 | 状态 | 字数(万字) | 热度(核心指标) | 最新更新 | 作品页链接 | 简介(截断100字)
98
+ 入口:qimao.com/paihang,男生榜/女生榜 tab 切换。类型:大热榜(日/月) / 新书榜 / 完结榜 / 收藏榜 / 更新榜
110
99
 
111
100
  ### 输出模板
112
101
 
@@ -118,90 +107,79 @@
118
107
 
119
108
  ---
120
109
 
121
- ### #{排名} {书名}
122
- *{作者} · {题材} · {分类标签} · {状态} · {字数}万字 · {热度}万热度*
123
- **最新更新:** {时间} · {章节}
124
-
125
- [作品页]({URL})
110
+ 书名:{书名}
111
+ 题材:{题材}
112
+ 作者:{作者}
113
+ 作品页:{URL}
126
114
 
127
- **简介**
128
- {简介原文}
115
+ 书名:{书名}
116
+ 题材:{题材}
117
+ 作者:{作者}
118
+ 作品页:{URL}
129
119
  ```
130
120
 
131
- ### 采集要点
132
-
133
- 无明显反爬需滚动加载。男生榜/女生榜tab切换,大热榜有日/月切换。
134
-
135
121
  ---
136
122
 
137
- ## 晋江
138
-
139
- ### 榜单URL
140
-
141
- `jjwxc.net/topten.php?orderstr={榜单ID}&t={频道ID}`(t=0全站,各频道ID从页面获取)
142
-
143
- | 榜单 | orderstr |
144
- |------|----------|
145
- | 收入金榜 | 12 |
146
- | 月榜 | 7 |
147
- | 季度榜 | 8 |
148
- | 完结金榜 | 14 |
149
- | 新手金榜 | 15 |
150
- | 千字金榜 | 17 |
123
+ ## 起点中文网
151
124
 
152
- ### 字段
125
+ ### 榜单
153
126
 
154
- 频道 | 排名 | 书名 | 作者 | novelid | 收藏数(核心) | 营养液 | 积分 | 字数 | 状态 | 作品页链接
127
+ SKILL.md「起点采集目标」表。优先使用移动端 SSR pageContext JSON,规避 PC 站风控。
155
128
 
156
129
  ### 输出模板
157
130
 
158
131
  ```markdown
159
- # 晋江 · {榜单名}
160
- - 来源:{topten URL}
132
+ # 起点 · {榜单名称}
133
+ - 来源:{榜单URL}
161
134
  - 抓取时间:{ISO 8601}
162
- - 频道数:{N} / 总条目数:{M}
163
- - 详情采集:{命中收藏数} / {计划数}(每频道前 {top},上限 {limit})
164
- - 数据质量:[OK / 详情解析异常·登录态缺失 / 仅列表-无核心指标]
135
+ - 条目数:{N}
165
136
 
166
137
  ---
167
138
 
168
- ## {频道名} — {N} 本
139
+ 书名:{书名}
140
+ 题材:{题材}
141
+ 作者:{作者}
142
+ 作品页:{URL}
169
143
 
170
- ### #{排名} {书名}
171
- *{作者} · 收藏 {X} · 营养液 {Y} · 积分 {Z} · 字数 {W}字 · {状态}*
172
- [作品页](https://www.jjwxc.net/onebook.php?novelid={id})
144
+ 书名:{书名}
145
+ 题材:{题材}
146
+ 作者:{作者}
147
+ 作品页:{URL}
173
148
  ```
174
149
 
175
- ### 采集要点
150
+ ---
176
151
 
177
- 两步:① 列表页 `topten.php` 取频道分组 + 书名/作者,从书名 anchor 取 `novelid`(排除"X向《书名》投了Y"霸王票记录);② 进 `onebook.php?novelid=` 详情页补采核心指标。
178
- - **编码**:晋江是 gb18030,详情页必须 `fetch+arrayBuffer+TextDecoder('gb18030')` 解码(同步 XHR 的 responseText 按 UTF-8 解码会乱码)。
179
- - **字段来源**:详情页 `itemprop` 微数据——`collectedCount`(收藏)/`nutritionCount`(营养液)/`scoreCount`(积分)/`wordCount`(字数)/`updataStatus`(状态)。这些是公开指标,**无需登录**。
180
- - **控量**:列表全量保留,仅每频道前 `--top` 本(受 `--detail-limit` 总量约束)补详情,避免对全站数百本逐一请求。
152
+ ## 知乎
181
153
 
182
- ---
154
+ ### 榜单
183
155
 
184
- ## 数据清洗
156
+ 入口:https://www.zhihu.com/fiore/h5/vip-web
157
+ 短篇4榜:推荐榜 / 热搜榜 / 热度榜 / 口碑榜
158
+ 长篇1榜:长篇榜
185
159
 
186
- 通用:移除平台模板文本→简介超100字在句号处截断加`...`→空值标`[待补]`
160
+ ### 输出模板
187
161
 
188
- | 平台 | 额外必填 |
189
- |------|----------|
190
- | 起点 | 题材、字数、总推荐 |
191
- | 番茄 | 在读数 |
192
- | 七猫 | 热度 |
193
- | 晋江 | 收藏数、营养液(或积分)、字数 |
162
+ ```markdown
163
+ # 知乎 · {短篇/长篇} · {榜单名}
164
+ - 来源:https://www.zhihu.com/fiore/h5/vip-web
165
+ - 抓取时间:{ISO 8601}
166
+ - 条目数:{N}
167
+
168
+ ---
194
169
 
195
- 最低采集量:主流平台15条,小平台10条。低于底线标`[数据稀疏]`。
170
+ 书名:{书名}
171
+ 题材:{题材}
172
+ 作者:{作者}
173
+ 作品页:{URL}
174
+
175
+ 书名:{书名}
176
+ 题材:{题材}
177
+ 作者:{作者}
178
+ 作品页:{URL}
179
+ ```
196
180
 
197
181
  ---
198
182
 
199
- ## 批量采集
183
+ ## 数据清洗
200
184
 
201
- | 平台 | 默认组合 |
202
- |------|----------|
203
- | 起点 | 新人签约新书榜+签约作者新书榜前20+月票榜前20+畅销榜前20 |
204
- | 番茄 | 男频阅读榜全题材+女频阅读榜全题材 |
205
- | 七猫 | 男频大热榜日榜+女频大热榜日榜 |
206
- | 晋江 | 收入金榜+月榜 |
207
- | 全平台 | 起点+番茄+七猫默认组合 |
185
+ 最低采集量:主流平台15条,小平台10条。低于底线标 `[数据稀疏]`。
@@ -390,7 +390,6 @@ async function scrapeChannel(ch, type) {
390
390
  "",
391
391
  `- 频道参数:channel=${ch},type=${type}`,
392
392
  `- 抓取时间:${now}`,
393
- `- 每题材上限 ≈ ${TOP}`,
394
393
  "",
395
394
  "---",
396
395
  "",
@@ -426,29 +425,15 @@ async function scrapeChannel(ch, type) {
426
425
  const info = details[String(b.bookId)] || {};
427
426
  totalBooks++;
428
427
  const resolved = !!info.title;
429
- if (resolved) resolvedTitles++;
430
428
 
431
429
  const title = info.title || "(标题待解析)";
432
430
  const author = info.author || "未知";
433
431
  const category = info.category || b.category || "";
434
- const catSeg = category ? ` · ${category}` : "";
435
-
436
- bodyLines.push(`### #${i + 1} ${title}`);
437
- bodyLines.push(
438
- `*${author}${catSeg} · ${fmtStatus(b.creationStatus)} · ${fmtReads(b.read_count)} 在读 · ${fmtWords(b.wordNumber)}字*`
439
- );
440
- if (info.tags) bodyLines.push(`**标签:** ${info.tags}`);
441
- bodyLines.push(`**最新更新:** ${b.lastChapterTitle || "未知"}`);
442
- bodyLines.push(`**bookId:** ${b.bookId}`);
443
- if (info.err) bodyLines.push(`⚠️ 详情:${info.err}`);
444
- bodyLines.push(`[作品页](https://fanqienovel.com/page/${b.bookId})`);
445
- const desc = cleanDesc(info.desc);
446
- if (desc) {
447
- bodyLines.push("");
448
- bodyLines.push("**简介**");
449
- bodyLines.push("");
450
- bodyLines.push(desc);
451
- }
432
+
433
+ bodyLines.push(`书名:${title}`);
434
+ bodyLines.push(`题材:${category}`);
435
+ bodyLines.push(`作者:${author}`);
436
+ bodyLines.push(`作品页:https://fanqienovel.com/page/${b.bookId}`);
452
437
  bodyLines.push("");
453
438
  }
454
439
 
@@ -461,26 +446,6 @@ async function scrapeChannel(ch, type) {
461
446
  }
462
447
  }
463
448
 
464
- const ratio = totalBooks ? resolvedTitles / totalBooks : 0;
465
- const quality =
466
- totalBooks === 0 ? "[无数据]" : ratio < 0.5 ? "[标题解析异常]" : "[OK]";
467
- lines.splice(
468
- 5,
469
- 0,
470
- `- 标题解析:成功 ${resolvedTitles} / 共 ${totalBooks}`,
471
- `- 数据质量:${quality}`
472
- );
473
-
474
- if (totalBooks > 0 && resolvedTitles === 0) {
475
- console.error(
476
- ` ✗ ${chLabel}${tyLabel}:${totalBooks} 本全部标题解析失败。请在浏览器内手动打开任一 https://fanqienovel.com/page/{bookId} 确认页面正常。`
477
- );
478
- } else if (ratio < 0.5) {
479
- console.error(
480
- ` ⚠ ${chLabel}${tyLabel}:标题解析率偏低(${resolvedTitles}/${totalBooks}),结果质量已标注。`
481
- );
482
- }
483
-
484
449
  scraped = lines.concat(bodyLines).join("\n");
485
450
  } finally {
486
451
  await browser.close();
@@ -255,31 +255,19 @@ async function scrapeRank(rankTypeId, channelId) {
255
255
  "",
256
256
  `- 来源:${url}`,
257
257
  `- 抓取时间:${now}`,
258
- `- 频道数:${data.channels.length}`,
259
- `- 总条目数:${totalBooks}`,
260
- `- 详情采集:${detailOk} / ${detailPlanned}`,
261
- `- 数据质量:${quality}`,
262
258
  "",
263
259
  "---",
264
260
  "",
265
261
  ];
266
262
 
267
263
  for (const ch of data.channels) {
268
- lines.push(`## ${ch.name} — ${ch.books.length} 本`, "");
264
+ lines.push(`## ${ch.name}`, "");
269
265
  for (let i = 0; i < ch.books.length; i++) {
270
266
  const b = ch.books[i];
271
- const d = b.novelid ? detailMap[b.novelid] : null;
272
- const seg = [b.author || ""];
273
- if (d) {
274
- if (d.collect) seg.push("收藏 " + fmtWan(d.collect));
275
- if (d.nutrition) seg.push("营养液 " + fmtWan(d.nutrition));
276
- if (d.score) seg.push("积分 " + d.score);
277
- if (d.words) seg.push("字数 " + fmtWan(d.words, "字"));
278
- if (d.status) seg.push(d.status);
279
- }
280
- const meta = seg.filter(Boolean).join(" · ");
281
- if (meta) lines.push(`*${meta}*`);
282
- if (b.novelid) lines.push(`[作品页](https://www.jjwxc.net/onebook.php?novelid=${b.novelid})`);
267
+ lines.push(`书名:${b.title || ""}`);
268
+ lines.push(`题材:${ch.name}`);
269
+ lines.push(`作者:${b.author || ""}`);
270
+ if (b.novelid) lines.push(`作品页:https://www.jjwxc.net/onebook.php?novelid=${b.novelid}`);
283
271
  lines.push("");
284
272
  }
285
273
  lines.push("---", "");
@@ -247,9 +247,6 @@ async function scrapeRank(channelId, rankTypeId, periodId) {
247
247
  const lines = [
248
248
  `# 七猫 · ${ch.label} · ${rt.label}${periodLabel}`,
249
249
  "",
250
- `- 数据质量:${summary.quality}`,
251
- `- 有效条目:${books.length} / ${rawCount}`,
252
- `- 问题摘要:${summary.problems.length ? summary.problems.join(";") : "无"}`,
253
250
  `- 来源:${url}`,
254
251
  `- 抓取时间:${now}`,
255
252
  "",
@@ -258,18 +255,11 @@ async function scrapeRank(channelId, rankTypeId, periodId) {
258
255
  ];
259
256
 
260
257
  for (const b of books) {
261
- lines.push(`### #${b.rank} ${b.title}`);
262
- const meta = [
263
- b.author || "[待补]", b.genre || "[待补]", b.subGenre || "[待补]",
264
- b.status || "[待补]", b.words || "[待补]",
265
- b.heat ? b.heat + "热度" : "[待补]",
266
- ].join(" · ");
267
- lines.push(`*${meta}*`);
268
- if (b.update) lines.push(`**最新更新:** ${b.update}`);
269
- if (b.url) lines.push(`[作品页](${b.url})`);
270
- const desc = cleanDesc(b.desc);
271
- if (desc) lines.push("", "**简介**", "", desc);
272
- lines.push("", "---", "");
258
+ lines.push(`书名:${b.title || ""}`);
259
+ lines.push(`题材:${b.genre || ""}`);
260
+ lines.push(`作者:${b.author || ""}`);
261
+ if (b.url) lines.push(`作品页:${b.url}`);
262
+ lines.push("");
273
263
  }
274
264
 
275
265
  return lines.join("\n");
@@ -134,22 +134,23 @@ async function scrapeBoard(board) {
134
134
 
135
135
  function buildBoardMarkdown(board, stories, date) {
136
136
  const lines = [
137
- `# 知乎${board.label}(${date})`,
137
+ `# 知乎 · ${board.label}`,
138
138
  "",
139
- `> 数据来源:${ENTRY_URL} → ${board.label}`,
140
- `> 篇幅:${LENGTH === "long" ? "长篇" : "短篇"}`,
141
- "> 知乎需要登录态才能看完整榜单,请确认已登录",
139
+ `- 来源:${ENTRY_URL}`,
140
+ `- 抓取时间:${date}`,
142
141
  "",
143
- `## ${board.label}内容`,
142
+ "---",
144
143
  "",
145
144
  ];
146
145
  if (!stories.length) {
147
146
  lines.push("(未提取到数据,可能页面结构变化或需要登录)", "", "---", "");
148
147
  } else {
149
148
  stories.forEach(s => {
150
- lines.push(`### ${s.rank}. ${s.title || "(无标题)"}`);
151
- if (s.url) lines.push(`- 链接:${s.url}`);
152
- lines.push("", "---", "");
149
+ lines.push(`书名:${s.title || ""}`);
150
+ lines.push(`题材:${LENGTH === "long" ? "长篇" : "短篇"}`);
151
+ lines.push(`作者:${s.author || ""}`);
152
+ if (s.url) lines.push(`作品页:${s.url}`);
153
+ lines.push("");
153
154
  });
154
155
  }
155
156
  return lines.join("\n");
@@ -101,14 +101,12 @@ export const scan = {
101
101
  fileList,
102
102
  ``,
103
103
  `请执行以下步骤:`,
104
+ `0. **禁止**使用覆盖的方式写文件,**必须**使用追加的方式`,
104
105
  `1. 读取上述生成的原始数据文件`,
105
106
  `2. 分析爆款书籍的题材、卖点、节奏、人设等特征`,
106
107
  `3. 生成扫榜报告(包含:市场趋势、热门题材分析、用户画像、竞争度评估)`,
107
108
  `4. 给出 3-5 个可行的选题方向建议`,
108
- `5. 先创建空文件(如果不存在),再追加报告内容:\n` +
109
- ` touch ${topicFile}\n` +
110
- ` echo "你的报告内容" >> ${topicFile}\n` +
111
- ` (使用 tee -a 或 >> ,不要覆盖现有内容)`,
109
+ `5. 将完整分析报告追加写入:${topicFile}`,
112
110
  ``,
113
111
  `报告要求:`,
114
112
  `- 客观分析数据,不臆测`,