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,侧边栏精简为小红书单入口
64 lines
2.8 KiB
TypeScript
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); });
|