修复 sec_user_id 抓取:同时解析请求 URL 与 body,修正关注按钮选择器

This commit is contained in:
Rabbit
2026-10-28 10:57:54 +08:00
parent f69fb95860
commit 201fcd7018
+52 -21
View File
@@ -1,4 +1,4 @@
// 获取抖音 Cookie 和 sec_user_id 的 Playwright 脚本 // 获取抖音 Cookie 和 sec_user_id 的 Playwright 脚本
// 用法: node get-cookie.js 或通过 cli.js cookies 调用 // 用法: node get-cookie.js 或通过 cli.js cookies 调用
// 首次运行扫码登录,后续运行浏览器会记住登录状态,无需重复扫码 // 首次运行扫码登录,后续运行浏览器会记住登录状态,无需重复扫码
@@ -128,24 +128,43 @@ async function openAndLogin(context) {
// ============================================================ // ============================================================
// 提取 sec_user_id // 提取 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) { async function extractSecUserId(page) {
return new Promise(async (resolve) => { return new Promise(async (resolve) => {
let found = null; let found = null;
page.on("request", (request) => { // 监听所有请求:既看 URL 查询串,也看 POST body
const onRequest = (request) => {
if (found) return;
try { 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(); const data = request.postData();
if (data && data.includes("sec_user_id")) { const fromBody = pickSecUserId(data);
const parsed = JSON.parse(data); if (fromBody) {
if (parsed.sec_user_id && !found) { found = fromBody;
found = parsed.sec_user_id; console.log("✅ 从请求 Body 捕获到 sec_user_id:", found);
console.log("✅ 从请求中捕获到 sec_user_id:", found);
}
} }
} catch (e) {} } catch (e) {}
}); };
page.on("request", onRequest);
// 尝试从页面获取 // 从页面本身尝试
await page.waitForTimeout(TIMEOUTS.pageWait); await page.waitForTimeout(TIMEOUTS.pageWait);
if (!found) { if (!found) {
try { try {
@@ -167,20 +186,32 @@ async function extractSecUserId(page) {
} catch (e) {} } catch (e) {}
} }
// 尝试点击关注按钮触发请求 // 兜底:主动点击头像旁边的「关注 / 关注列表」按钮,触发 following/list 请求
// 抖音此按钮有多种 data-e2e,逐个尝试
if (!found) { if (!found) {
console.log("🖱️ 尝试点击关注按钮..."); const selectors = [
try { '[data-e2e="following-count"]', // 关注数(点它弹关注列表)
const btn = page.locator('[data-e2e="follow-count"]').first(); '[data-e2e="user-info-follow"]', // 关注按钮
if (await btn.isVisible({ timeout: TIMEOUTS.elementVisible })) { 'span:has-text("关注")',
await btn.click(); ];
await page.waitForTimeout(TIMEOUTS.pageWait); for (const sel of selectors) {
} if (found) break;
} catch (e) {} 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); resolve(found);
}); });
} }