tt-help-cli-ycl 1.3.49 → 1.3.50
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 +1 -1
- package/src/cli/open.js +3 -5
- package/src/lib/tiktok-scraper.mjs +32 -46
package/package.json
CHANGED
package/src/cli/open.js
CHANGED
|
@@ -33,15 +33,13 @@ export async function handleOpen(parsed) {
|
|
|
33
33
|
if (!openPort) {
|
|
34
34
|
console.error("用法: tt-help open <端口>");
|
|
35
35
|
console.error("示例: tt-help open 9222");
|
|
36
|
-
console.error("");
|
|
37
|
-
console.error("可用端口: 9222 - 9231 (共 10 个)");
|
|
38
|
-
console.error('运行 "tt-help open --list" 查看所有配置');
|
|
36
|
+
console.error('运行 "tt-help open --list" 查看所有内置配置');
|
|
39
37
|
process.exit(1);
|
|
40
38
|
}
|
|
41
39
|
|
|
42
40
|
const port = parseInt(openPort);
|
|
43
|
-
if (isNaN(port) || port <
|
|
44
|
-
console.error(`端口 ${openPort}
|
|
41
|
+
if (isNaN(port) || port < 1 || port > 65535) {
|
|
42
|
+
console.error(`端口 ${openPort} 无效,请输入 1-65535 之间的端口号`);
|
|
45
43
|
process.exit(1);
|
|
46
44
|
}
|
|
47
45
|
|
|
@@ -9,7 +9,7 @@ const DEFAULT_WAF_TTL = 120000;
|
|
|
9
9
|
const DEFAULT_WARM_URL = "https://www.tiktok.com/@nike";
|
|
10
10
|
const BROWSER_CLOSE_TIMEOUT = 5000;
|
|
11
11
|
const DEFAULT_MAX_REQUESTS_PER_PAGE = 50;
|
|
12
|
-
const FALLBACK_PROFILE_PORT =
|
|
12
|
+
const FALLBACK_PROFILE_PORT = 9999;
|
|
13
13
|
|
|
14
14
|
function delay(ms) {
|
|
15
15
|
return new Promise((r) => setTimeout(r, ms));
|
|
@@ -120,10 +120,11 @@ export class TikTokScraper {
|
|
|
120
120
|
this.slotIdx = 0;
|
|
121
121
|
this.lastWarmTime = 0;
|
|
122
122
|
this.warmPromise = null;
|
|
123
|
-
|
|
124
|
-
this.
|
|
125
|
-
this.
|
|
126
|
-
this.
|
|
123
|
+
// 登录态 pool(init 时直接启动)
|
|
124
|
+
this.authBrowser = null;
|
|
125
|
+
this.authContext = null;
|
|
126
|
+
this.authSlots = [];
|
|
127
|
+
this.authSlotIdx = 0;
|
|
127
128
|
}
|
|
128
129
|
|
|
129
130
|
async init() {
|
|
@@ -141,23 +142,19 @@ export class TikTokScraper {
|
|
|
141
142
|
this.browser = browser;
|
|
142
143
|
this.context = context;
|
|
143
144
|
this.slots = slots;
|
|
144
|
-
await this.warmWaf();
|
|
145
|
-
}
|
|
146
145
|
|
|
147
|
-
|
|
148
|
-
if (this._fallbackContext) return;
|
|
146
|
+
// 启动登录态 pool(1 个 slot)
|
|
149
147
|
const fallbackDir = getFallbackProfileDir();
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
this.
|
|
160
|
-
this._fallbackSlots = slots;
|
|
148
|
+
const {
|
|
149
|
+
browser: authBrowser,
|
|
150
|
+
context: authContext,
|
|
151
|
+
slots: authSlots,
|
|
152
|
+
} = await initContext(executablePath, 1, fallbackDir);
|
|
153
|
+
this.authBrowser = authBrowser;
|
|
154
|
+
this.authContext = authContext;
|
|
155
|
+
this.authSlots = authSlots;
|
|
156
|
+
|
|
157
|
+
await this.warmWaf();
|
|
161
158
|
}
|
|
162
159
|
|
|
163
160
|
async close() {
|
|
@@ -183,20 +180,20 @@ export class TikTokScraper {
|
|
|
183
180
|
}
|
|
184
181
|
};
|
|
185
182
|
|
|
186
|
-
// 无登录态的 browser
|
|
183
|
+
// 无登录态的 browser
|
|
187
184
|
await closeAll(this.browser);
|
|
188
|
-
//
|
|
189
|
-
if (this.
|
|
185
|
+
// 登录态的 context(launchPersistentContext 返回的是 context 当 browser)
|
|
186
|
+
if (this.authContext) {
|
|
190
187
|
try {
|
|
191
|
-
await this.
|
|
188
|
+
await this.authContext.close();
|
|
192
189
|
} catch {}
|
|
193
190
|
}
|
|
194
191
|
this.browser = null;
|
|
195
192
|
this.context = null;
|
|
196
193
|
this.slots = [];
|
|
197
|
-
this.
|
|
198
|
-
this.
|
|
199
|
-
this.
|
|
194
|
+
this.authBrowser = null;
|
|
195
|
+
this.authContext = null;
|
|
196
|
+
this.authSlots = [];
|
|
200
197
|
}
|
|
201
198
|
|
|
202
199
|
async restart() {
|
|
@@ -237,11 +234,6 @@ export class TikTokScraper {
|
|
|
237
234
|
return Date.now() - this.lastWarmTime > this.wafTtl;
|
|
238
235
|
}
|
|
239
236
|
|
|
240
|
-
_pickSlot(slots, idx, setIdx) {
|
|
241
|
-
const slot = slots[idx % slots.length];
|
|
242
|
-
return slot;
|
|
243
|
-
}
|
|
244
|
-
|
|
245
237
|
async _ensurePage(slot, context) {
|
|
246
238
|
try {
|
|
247
239
|
if (
|
|
@@ -258,13 +250,11 @@ export class TikTokScraper {
|
|
|
258
250
|
}
|
|
259
251
|
|
|
260
252
|
async _fetchViewSource(url, ctx) {
|
|
261
|
-
const slots =
|
|
262
|
-
|
|
263
|
-
const slotIdx =
|
|
264
|
-
ctx === this._fallbackContext ? this._fallbackSlotIdx : this.slotIdx;
|
|
253
|
+
const slots = ctx === this.authContext ? this.authSlots : this.slots;
|
|
254
|
+
const slotIdx = ctx === this.authContext ? this.authSlotIdx : this.slotIdx;
|
|
265
255
|
const slot = slots[slotIdx % slots.length];
|
|
266
|
-
if (ctx === this.
|
|
267
|
-
this.
|
|
256
|
+
if (ctx === this.authContext) {
|
|
257
|
+
this.authSlotIdx++;
|
|
268
258
|
} else {
|
|
269
259
|
this.slotIdx++;
|
|
270
260
|
}
|
|
@@ -329,11 +319,9 @@ export class TikTokScraper {
|
|
|
329
319
|
result = rawHtml ? parseUserInfo(rawHtml) : null;
|
|
330
320
|
}
|
|
331
321
|
|
|
332
|
-
//
|
|
322
|
+
// 仍然失败:使用登录态 pool
|
|
333
323
|
if (!result) {
|
|
334
|
-
|
|
335
|
-
await this._ensureFallback(executablePath);
|
|
336
|
-
rawHtml = await this._fetchViewSource(url, this._fallbackContext);
|
|
324
|
+
rawHtml = await this._fetchViewSource(url, this.authContext);
|
|
337
325
|
result = rawHtml ? parseUserInfo(rawHtml) : null;
|
|
338
326
|
}
|
|
339
327
|
|
|
@@ -354,11 +342,9 @@ export class TikTokScraper {
|
|
|
354
342
|
result = rawHtml ? parseVideoInfo(rawHtml) : null;
|
|
355
343
|
}
|
|
356
344
|
|
|
357
|
-
//
|
|
345
|
+
// 仍然失败:使用登录态 pool
|
|
358
346
|
if (!result) {
|
|
359
|
-
|
|
360
|
-
await this._ensureFallback(executablePath);
|
|
361
|
-
rawHtml = await this._fetchViewSource(videoUrl, this._fallbackContext);
|
|
347
|
+
rawHtml = await this._fetchViewSource(videoUrl, this.authContext);
|
|
362
348
|
result = rawHtml ? parseVideoInfo(rawHtml) : null;
|
|
363
349
|
}
|
|
364
350
|
|