front/xhs-agent-desktop/engine/scripts/xhs/user_profile.py
zzh 5a26ae0048 feat: 小红书模块迁移、登录重构与 xhs-agent-desktop 桌面 Agent
- 新增小红书前端模块(启动服务、内容分析、爆款创作、发布记录、技能卡片、拟人设置、AI 助手)

- 新增 xhs-agent-desktop 独立桌面 Agent,对接 OMS 任务调度

- 登录页重构,整合微信登录与 OMS JWT 认证

- 订单、渠道、用户中心等页面与 API 增强

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-30 16:13:13 +08:00

112 lines
3.3 KiB
Python

"""用户主页,对应 Go xiaohongshu/user_profile.go。"""
from __future__ import annotations
import json
import logging
import time
from .cdp import Page
from .types import Feed, UserBasicInfo, UserInteraction, UserProfileResponse
from .urls import make_user_profile_url
logger = logging.getLogger(__name__)
# 提取用户数据的 JS
_EXTRACT_USER_DATA_JS = """
(() => {
if (window.__INITIAL_STATE__ &&
window.__INITIAL_STATE__.user &&
window.__INITIAL_STATE__.user.userPageData) {
const userPageData = window.__INITIAL_STATE__.user.userPageData;
const data = userPageData.value !== undefined ? userPageData.value : userPageData._value;
if (data) {
return JSON.stringify(data);
}
}
return "";
})()
"""
_EXTRACT_USER_NOTES_JS = """
(() => {
if (window.__INITIAL_STATE__ &&
window.__INITIAL_STATE__.user &&
window.__INITIAL_STATE__.user.notes) {
const notes = window.__INITIAL_STATE__.user.notes;
const data = notes.value !== undefined ? notes.value : notes._value;
if (data) {
return JSON.stringify(data);
}
}
return "";
})()
"""
def get_user_profile(page: Page, user_id: str, xsec_token: str) -> UserProfileResponse:
"""获取用户主页信息及帖子。
Args:
page: CDP 页面对象。
user_id: 用户 ID。
xsec_token: xsec_token。
Raises:
RuntimeError: 数据提取失败。
"""
url = make_user_profile_url(user_id, xsec_token)
page.navigate(url)
page.wait_for_load()
page.wait_dom_stable()
return _extract_user_profile_data(page)
def _extract_user_profile_data(page: Page) -> UserProfileResponse:
"""从页面提取用户资料数据。"""
# 等待 __INITIAL_STATE__
_wait_for_initial_state(page)
# 提取用户信息
user_data_result = page.evaluate(_EXTRACT_USER_DATA_JS)
if not user_data_result:
raise RuntimeError("user.userPageData.value not found in __INITIAL_STATE__")
# 提取用户帖子
notes_result = page.evaluate(_EXTRACT_USER_NOTES_JS)
if not notes_result:
raise RuntimeError("user.notes.value not found in __INITIAL_STATE__")
# 解析用户信息
user_page_data = json.loads(user_data_result)
basic_info = UserBasicInfo.from_dict(user_page_data.get("basicInfo", {}))
interactions = [UserInteraction.from_dict(i) for i in user_page_data.get("interactions", [])]
# 解析帖子(双重数组,展平)
notes_feeds_raw = json.loads(notes_result)
feeds: list[Feed] = []
for feed_group in notes_feeds_raw:
if isinstance(feed_group, list):
for f in feed_group:
feeds.append(Feed.from_dict(f))
elif isinstance(feed_group, dict):
feeds.append(Feed.from_dict(feed_group))
return UserProfileResponse(
user_basic_info=basic_info,
interactions=interactions,
feeds=feeds,
)
def _wait_for_initial_state(page: Page, timeout: float = 10.0) -> None:
"""等待 __INITIAL_STATE__ 就绪。"""
deadline = time.monotonic() + timeout
while time.monotonic() < deadline:
ready = page.evaluate("window.__INITIAL_STATE__ !== undefined")
if ready:
return
time.sleep(0.5)
logger.warning("等待 __INITIAL_STATE__ 超时")