修复 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 调用
// 首次运行扫码登录,后续运行浏览器会记住登录状态,无需重复扫码
@@ -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);
});
}