Files
kurihada 9d0a9c93f4 整合小红书页面:内联扫码登录、用户主页、移除独立登录和内容浏览页
- 新增 XiaohongshuPage:顶部搜索栏、登录用户头像/ID、退出按钮
- 未登录时内联显示二维码,无需跳转独立登录页
- 点击笔记作者可打开用户主页 slide-over(复用 UserCard)
- 修复用户主页关注/粉丝/获赞数为零:选择器从 .data-area .data-item 改为 .user-interactions > div
- 修复用户头像选择器:img.user-image(img 本身带该 class)
- backend LoginStatus 新增 avatar/userId 字段,登录状态接口返回头像和用户 ID
- 删除 LoginPage、BrowserPage,侧边栏精简为小红书单入口
2026-03-02 00:12:24 +08:00

64 lines
2.8 KiB
TypeScript

import { chromium } from 'rebrowser-playwright';
import { readFileSync } from 'node:fs';
const COOKIE_FILE = `${process.env.HOME}/.social-mcp/xiaohongshu/cookies.json`;
const userId = '5b29b622e8ac2b5a12ae97fc';
const xsecToken = 'ABrhIpSL55O66wuekMtlJUxsX4EpaNTlfCYwDo6UfKrrM=';
async function main() {
const raw = JSON.parse(readFileSync(COOKIE_FILE, 'utf-8'));
const browser = await chromium.launch({ headless: true, args: ['--no-sandbox','--disable-setuid-sandbox','--disable-dev-shm-usage','--disable-gpu'] });
const ctx = await browser.newContext({ storageState: raw });
const page = await ctx.newPage();
// Warm up: visit explore first
console.log('Warming up: visiting explore...');
await page.goto('https://www.xiaohongshu.com/explore', { waitUntil: 'domcontentloaded' });
await page.waitForTimeout(2000);
console.log('Explore title:', await page.title());
// Now try profile with pc_feed source (matching the token's source)
const url = `https://www.xiaohongshu.com/user/profile/${userId}?xsec_token=${encodeURIComponent(xsecToken)}&xsec_source=pc_feed`;
console.log('\nNavigating to profile (xsec_source=pc_feed)...');
await page.goto(url, { waitUntil: 'domcontentloaded' });
await page.waitForTimeout(2000);
console.log('title:', await page.title());
console.log('url:', page.url().slice(0, 80));
const nickname = await page.$eval('.user-info .user-name', el => el.textContent?.trim() ?? '').catch(() => 'NOT FOUND');
console.log('nickname:', nickname);
// Check __INITIAL_STATE__
const initialState = await page.evaluate(() => {
const s = (window as unknown as Record<string, unknown>).__INITIAL_STATE__;
return s ? JSON.stringify(s) : null;
}).catch(() => null);
if (!initialState) {
console.log('__INITIAL_STATE__: NOT FOUND');
} else {
const state = JSON.parse(initialState);
const keys = Object.keys(state);
console.log('\n__INITIAL_STATE__ top-level keys:', keys);
// Dump user / userProfile subtrees
if (state.user) console.log('\nstate.user keys:', Object.keys(state.user));
if (state.user?.userPageData) {
const upd = state.user.userPageData;
console.log('\nstate.user.userPageData keys:', Object.keys(upd));
console.log(' basicInfo:', JSON.stringify(upd.basicInfo)?.slice(0, 300));
console.log(' interactions:', JSON.stringify(upd.interactions));
console.log(' noteCount:', upd.noteCount, '/ note_count:', upd.note_count);
}
if (state.userProfile) {
console.log('\nstate.userProfile keys:', Object.keys(state.userProfile));
console.log(' userInfo:', JSON.stringify(state.userProfile.userInfo)?.slice(0, 300));
}
}
const feeds = await page.$$('.feeds-container .note-item');
console.log('\nnote items:', feeds.length);
await browser.close();
}
main().catch(e => { console.error(e); process.exit(1); });