diff --git a/handlers_api.go b/handlers_api.go index 41deec6..79a2a97 100644 --- a/handlers_api.go +++ b/handlers_api.go @@ -227,3 +227,17 @@ func healthHandler(c *gin.Context) { "timestamp": "now", }, "服务正常") } + +// myProfileHandler 我的信息 +func (s *AppServer) myProfileHandler(c *gin.Context) { + // 获取当前登录用户信息 + result, err := s.xiaohongshuService.GetMyProfile(c.Request.Context()) + if err != nil { + respondError(c, http.StatusInternalServerError, "GET_MY_PROFILE_FAILED", + "获取我的主页失败", err.Error()) + return + } + + c.Set("account", "ai-report") + respondSuccess(c, map[string]any{"data": result}, "获取我的主页成功") +} diff --git a/routes.go b/routes.go index 4d87dd1..58ff566 100644 --- a/routes.go +++ b/routes.go @@ -48,6 +48,7 @@ func setupRoutes(appServer *AppServer) *gin.Engine { api.POST("/feeds/detail", appServer.getFeedDetailHandler) api.POST("/user/profile", appServer.userProfileHandler) api.POST("/feeds/comment", appServer.postCommentHandler) + api.GET("/user/me", appServer.myProfileHandler) } return router diff --git a/service.go b/service.go index f2a37b4..ce9c368 100644 --- a/service.go +++ b/service.go @@ -461,3 +461,38 @@ func saveCookies(page *rod.Page) error { cookieLoader := cookies.NewLoadCookie(cookies.GetCookiesFilePath()) return cookieLoader.SaveCookies(data) } + +// withBrowserPage 执行需要浏览器页面的操作的通用函数 +func withBrowserPage(fn func(*rod.Page) error) error { + b := newBrowser() + defer b.Close() + + page := b.NewPage() + defer page.Close() + + return fn(page) +} + +// GetMyProfile 获取当前登录用户的个人信息 +func (s *XiaohongshuService) GetMyProfile(ctx context.Context) (*UserProfileResponse, error) { + var result *xiaohongshu.UserProfileResponse + var err error + + err = withBrowserPage(func(page *rod.Page) error { + action := xiaohongshu.NewUserProfileAction(page) + result, err = action.GetMyProfileViaSidebar(ctx) + return err + }) + + if err != nil { + return nil, err + } + + response := &UserProfileResponse{ + UserBasicInfo: result.UserBasicInfo, + Interactions: result.Interactions, + Feeds: result.Feeds, + } + + return response, nil +} diff --git a/xiaohongshu/navigate.go b/xiaohongshu/navigate.go index ba9166a..00791ce 100644 --- a/xiaohongshu/navigate.go +++ b/xiaohongshu/navigate.go @@ -23,3 +23,23 @@ func (n *NavigateAction) ToExplorePage(ctx context.Context) error { return nil } + +func (n *NavigateAction) ToProfilePage(ctx context.Context) error { + page := n.page.Context(ctx) + + // First navigate to explore page + if err := n.ToExplorePage(ctx); err != nil { + return err + } + + page.MustWaitStable() + + // Find and click the "我" channel link in sidebar + profileLink := page.MustElement(`div.main-container li.user.side-bar-component a.link-wrapper span.channel`) + profileLink.MustClick() + + // Wait for navigation to complete + page.MustWaitLoad() + + return nil +} diff --git a/xiaohongshu/user_profile.go b/xiaohongshu/user_profile.go index d60d3d8..df4af88 100644 --- a/xiaohongshu/user_profile.go +++ b/xiaohongshu/user_profile.go @@ -26,6 +26,11 @@ func (u *UserProfileAction) UserProfile(ctx context.Context, userID, xsecToken s page.MustNavigate(searchURL) page.MustWaitStable() + return u.extractUserProfileData(page) +} + +// extractUserProfileData 从页面中提取用户资料数据的通用方法 +func (u *UserProfileAction) extractUserProfileData(page *rod.Page) (*UserProfileResponse, error) { page.MustWait(`() => window.__INITIAL_STATE__ !== undefined`) // 获取 window.__INITIAL_STATE__ 并转换为 JSON 字符串 @@ -69,3 +74,20 @@ func (u *UserProfileAction) UserProfile(ctx context.Context, userID, xsecToken s func makeUserProfileURL(userID, xsecToken string) string { return fmt.Sprintf("https://www.xiaohongshu.com/user/profile/%s?xsec_token=%s&xsec_source=pc_note", userID, xsecToken) } + +func (u *UserProfileAction) GetMyProfileViaSidebar(ctx context.Context) (*UserProfileResponse, error) { + page := u.page.Context(ctx) + + // 创建导航动作 + navigate := NewNavigate(page) + + // 通过侧边栏导航到个人主页 + if err := navigate.ToProfilePage(ctx); err != nil { + return nil, fmt.Errorf("failed to navigate to profile page via sidebar: %w", err) + } + + // 等待页面加载完成并获取 __INITIAL_STATE__ + page.MustWaitStable() + + return u.extractUserProfileData(page) +}