tt-help-cli-ycl 1.4.45 → 1.4.47
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/lib/shop-scraper.mjs +116 -39
package/package.json
CHANGED
package/src/lib/shop-scraper.mjs
CHANGED
|
@@ -83,58 +83,135 @@ function extractJsonByKey(html, keyPattern) {
|
|
|
83
83
|
|
|
84
84
|
/**
|
|
85
85
|
* Windows: 后台服务的 Playwright 浏览器在 Session 0(隔离桌面),
|
|
86
|
-
* RDP
|
|
86
|
+
* RDP 看不到。找到交互桌面 Session,用计划任务推到那个 Session。
|
|
87
|
+
* 配置环境变量(可选):
|
|
88
|
+
* CAPTCHA_RECOVERY_USER - schtasks /ru 用户名(必需,否则无法跨 Session)
|
|
89
|
+
* CAPTCHA_RECOVERY_PASS - schtasks /rp 密码
|
|
87
90
|
*/
|
|
91
|
+
let winRecoveryRunning = false;
|
|
92
|
+
|
|
88
93
|
async function resolveCaptchaWindows(url, proxyUrl) {
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
execSync(`start "" "microsoft-edge:${edgeUrl}"`, {
|
|
93
|
-
shell: "cmd.exe",
|
|
94
|
-
timeout: 5000,
|
|
95
|
-
});
|
|
96
|
-
console.error(
|
|
97
|
-
"[shop-scraper] Windows: 已用 start 命令在交互桌面打开 Edge,请在 RDP 中完成验证码",
|
|
98
|
-
);
|
|
99
|
-
} catch (e) {
|
|
100
|
-
console.error("[shop-scraper] Windows: start 命令失败:", e.message);
|
|
94
|
+
if (winRecoveryRunning) {
|
|
95
|
+
console.error("[shop-scraper] Windows: 验证码恢复已在运行,跳过");
|
|
96
|
+
return false;
|
|
101
97
|
}
|
|
98
|
+
winRecoveryRunning = true;
|
|
102
99
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
const POLL_MS = 5000;
|
|
107
|
-
const MAX_WAIT_MS = 3600_000; // 最长等 1 小时
|
|
108
|
-
const start = Date.now();
|
|
100
|
+
try {
|
|
101
|
+
const edgeUrl = url.replace("shop.tiktok.com", "www.tiktok.com/shop/pdp");
|
|
102
|
+
const taskName = "TikTokCaptchaRecovery";
|
|
109
103
|
|
|
110
|
-
|
|
111
|
-
|
|
104
|
+
// 1. 找到 RDP 交互桌面 Session(Active 且非 Session 0)
|
|
105
|
+
let sessionId = null;
|
|
112
106
|
try {
|
|
113
|
-
const
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
const
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
107
|
+
const sessions = execSync(
|
|
108
|
+
`powershell -NoProfile -Command "query session 2>$null | findstr Active"`,
|
|
109
|
+
{ shell: "cmd.exe", timeout: 5000, encoding: "utf-8" },
|
|
110
|
+
);
|
|
111
|
+
const lines = sessions.trim().split("\n");
|
|
112
|
+
for (const line of lines) {
|
|
113
|
+
// 匹配 RDP 会话: ">rdp-tcp#1 username 2 Active"
|
|
114
|
+
const match = line.match(/\s(\d+)\s+Active/);
|
|
115
|
+
if (match && match[1] !== "0") {
|
|
116
|
+
sessionId = parseInt(match[1], 10);
|
|
117
|
+
break;
|
|
118
|
+
}
|
|
124
119
|
}
|
|
125
120
|
} catch {
|
|
126
|
-
|
|
121
|
+
console.error("[shop-scraper] Windows: 无法获取交互 Session");
|
|
127
122
|
}
|
|
128
|
-
|
|
129
|
-
if (
|
|
123
|
+
|
|
124
|
+
if (sessionId) {
|
|
130
125
|
console.error(
|
|
131
|
-
`[shop-scraper]
|
|
126
|
+
`[shop-scraper] Windows: Session ${sessionId},用计划任务启动 Edge`,
|
|
132
127
|
);
|
|
128
|
+
// 清理旧任务
|
|
129
|
+
try {
|
|
130
|
+
execSync(`schtasks /delete /tn "${taskName}" /f 2>$null`, {
|
|
131
|
+
shell: "cmd.exe",
|
|
132
|
+
});
|
|
133
|
+
} catch {}
|
|
134
|
+
|
|
135
|
+
const taskUser = process.env.CAPTCHA_RECOVERY_USER || "";
|
|
136
|
+
const taskPass = process.env.CAPTCHA_RECOVERY_PASS || "";
|
|
137
|
+
|
|
138
|
+
if (taskUser && taskPass) {
|
|
139
|
+
// 跨 Session:指定用户 + 交互模式
|
|
140
|
+
const today = new Date().toISOString().slice(0, 10).replace(/-/g, "/");
|
|
141
|
+
execSync(
|
|
142
|
+
`schtasks /create /tn "${taskName}" /tr "msedge \\"${edgeUrl}\\"" /sc once /sd ${today} /st 00:00 /ru "${taskUser}" /rp "${taskPass}" /it /f`,
|
|
143
|
+
{ shell: "cmd.exe", timeout: 10000 },
|
|
144
|
+
);
|
|
145
|
+
} else {
|
|
146
|
+
// 回退:无凭证时只能当前 Session(如果 webserver 从 RDP 启动才能看到)
|
|
147
|
+
console.error(
|
|
148
|
+
"[shop-scraper] Windows: 未设置 CAPTCHA_RECOVERY_USER/PASS,计划任务仅限当前 Session",
|
|
149
|
+
);
|
|
150
|
+
execSync(
|
|
151
|
+
`schtasks /create /tn "${taskName}" /tr "msedge \\"${edgeUrl}\\"" /sc once /st 00:00 /it /f`,
|
|
152
|
+
{ shell: "cmd.exe", timeout: 10000 },
|
|
153
|
+
);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
execSync(`schtasks /run /tn "${taskName}"`, {
|
|
157
|
+
shell: "cmd.exe",
|
|
158
|
+
timeout: 10000,
|
|
159
|
+
});
|
|
160
|
+
setTimeout(() => {
|
|
161
|
+
try {
|
|
162
|
+
execSync(`schtasks /delete /tn "${taskName}" /f 2>$null`, {
|
|
163
|
+
shell: "cmd.exe",
|
|
164
|
+
});
|
|
165
|
+
} catch {}
|
|
166
|
+
}, 10000);
|
|
167
|
+
} else {
|
|
168
|
+
console.error(
|
|
169
|
+
"[shop-scraper] Windows: 未找到交互 Session,尝试直接 start",
|
|
170
|
+
);
|
|
171
|
+
try {
|
|
172
|
+
execSync(`start "" "microsoft-edge:${edgeUrl}"`, {
|
|
173
|
+
shell: "cmd.exe",
|
|
174
|
+
timeout: 5000,
|
|
175
|
+
});
|
|
176
|
+
} catch {}
|
|
133
177
|
}
|
|
134
|
-
}
|
|
135
178
|
|
|
136
|
-
|
|
137
|
-
|
|
179
|
+
// 2. 轮询 undici 等待 IP 信用恢复
|
|
180
|
+
const proxy = proxyUrl || DEFAULT_PROXY;
|
|
181
|
+
const agent = proxy ? new ProxyAgent(proxy) : null;
|
|
182
|
+
const POLL_MS = 5000;
|
|
183
|
+
const MAX_WAIT_MS = 3600_000;
|
|
184
|
+
const startTime = Date.now();
|
|
185
|
+
|
|
186
|
+
while (Date.now() - startTime < MAX_WAIT_MS) {
|
|
187
|
+
await new Promise((r) => setTimeout(r, POLL_MS));
|
|
188
|
+
try {
|
|
189
|
+
const { body } = await request(url, {
|
|
190
|
+
headers: PDP_HEADERS,
|
|
191
|
+
...(agent ? { dispatcher: agent } : {}),
|
|
192
|
+
});
|
|
193
|
+
const html = await body.text();
|
|
194
|
+
if (
|
|
195
|
+
html.includes('"product_model"') ||
|
|
196
|
+
html.includes('"review_ratings"')
|
|
197
|
+
) {
|
|
198
|
+
console.error("[shop-scraper] Captcha solved, IP credit restored");
|
|
199
|
+
return true;
|
|
200
|
+
}
|
|
201
|
+
} catch {}
|
|
202
|
+
const waited = Math.round((Date.now() - startTime) / 60000);
|
|
203
|
+
if (waited > 0 && waited % 5 === 0) {
|
|
204
|
+
console.error(
|
|
205
|
+
`[shop-scraper] 等待验证码解决中... 已等待 ${waited} 分钟`,
|
|
206
|
+
);
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
console.error("[shop-scraper] Windows: 等待验证码超时");
|
|
211
|
+
return false;
|
|
212
|
+
} finally {
|
|
213
|
+
winRecoveryRunning = false;
|
|
214
|
+
}
|
|
138
215
|
}
|
|
139
216
|
|
|
140
217
|
/**
|