diff --git a/src/get-cookie.js b/src/get-cookie.js index bd5d4b2..23627d5 100644 --- a/src/get-cookie.js +++ b/src/get-cookie.js @@ -1,4 +1,4 @@ -// 获取抖音 Cookie 和 sec_user_id 的 Playwright 脚本 +// 获取抖音 Cookie 和 sec_user_id 的 Playwright 脚本 // 用法: node get-cookie.js 或通过 cli.js cookies 调用 // 首次运行扫码登录,后续运行浏览器会记住登录状态,无需重复扫码 @@ -128,24 +128,43 @@ async function openAndLogin(context) { // ============================================================ // 提取 sec_user_id // ============================================================ +// 从任意文本/URL 中提取 sec_user_id +// 兼容:URL query ?sec_user_id=xxx / JSON body "sec_user_id":"xxx" +function pickSecUserId(text) { + if (!text) return null; + // 匹配 sec_user_id=xxx 或 "sec_user_id":"xxx" + const m = text.match(/sec_user_id(?:=|%3D|":"|%22:%22|\":\")([^&"'\s]+)/i); + if (m && m[1] && m[1] !== "self") return decodeURIComponent(m[1]); + return null; +} + async function extractSecUserId(page) { return new Promise(async (resolve) => { let found = null; - page.on("request", (request) => { + // 监听所有请求:既看 URL 查询串,也看 POST body + const onRequest = (request) => { + if (found) return; try { + // 1) 优先看 URL(following/list 等 GET 请求的 sec_user_id 在这里) + const fromUrl = pickSecUserId(request.url()); + if (fromUrl) { + found = fromUrl; + console.log("✅ 从请求 URL 捕获到 sec_user_id:", found); + return; + } + // 2) 再看 POST body const data = request.postData(); - if (data && data.includes("sec_user_id")) { - const parsed = JSON.parse(data); - if (parsed.sec_user_id && !found) { - found = parsed.sec_user_id; - console.log("✅ 从请求中捕获到 sec_user_id:", found); - } + const fromBody = pickSecUserId(data); + if (fromBody) { + found = fromBody; + console.log("✅ 从请求 Body 捕获到 sec_user_id:", found); } } catch (e) {} - }); + }; + page.on("request", onRequest); - // 尝试从页面获取 + // 从页面本身尝试 await page.waitForTimeout(TIMEOUTS.pageWait); if (!found) { try { @@ -167,20 +186,32 @@ async function extractSecUserId(page) { } catch (e) {} } - // 尝试点击关注按钮触发请求 + // 兜底:主动点击头像旁边的「关注 / 关注列表」按钮,触发 following/list 请求 + // 抖音此按钮有多种 data-e2e,逐个尝试 if (!found) { - console.log("🖱️ 尝试点击关注按钮..."); - try { - const btn = page.locator('[data-e2e="follow-count"]').first(); - if (await btn.isVisible({ timeout: TIMEOUTS.elementVisible })) { - await btn.click(); - await page.waitForTimeout(TIMEOUTS.pageWait); - } - } catch (e) {} + const selectors = [ + '[data-e2e="following-count"]', // 关注数(点它弹关注列表) + '[data-e2e="user-info-follow"]', // 关注按钮 + 'span:has-text("关注")', + ]; + for (const sel of selectors) { + if (found) break; + console.log(`🖱️ 尝试点击关注入口: ${sel}`); + try { + const btn = page.locator(sel).first(); + if (await btn.isVisible({ timeout: TIMEOUTS.elementVisible }).catch(() => false)) { + await btn.click().catch(() => {}); + // 触发后再多等一会儿收集请求 + await page.waitForTimeout(TIMEOUTS.pageWait); + } + } catch (e) {} + } } - // 等最后 3 秒收集网络请求 - await page.waitForTimeout(TIMEOUTS.pageWait); + // 再等一会儿收集网络请求 + if (!found) await page.waitForTimeout(TIMEOUTS.pageWait); + + page.off("request", onRequest); resolve(found); }); }