123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449 |
- package service
- import (
- "context"
- "encoding/json"
- "errors"
- "fmt"
- "io/ioutil"
- "net/http"
- "strconv"
- "strings"
- )
- // RedBookNoteResponse 小红书链接接收结构体
- type RedBookNoteResponse struct {
- Code int `json:"code"`
- Data struct {
- ResponseBody struct {
- Data struct {
- Items []struct {
- NoteCard struct {
- InteractInfo struct {
- LikedCount string `json:"liked_count"` // 点赞数
- CommentCount string `json:"comment_count"` // 评论数
- CollectedCount string `json:"collected_count"` // 收藏数
- ShareCount string `json:"share_count"` // 分享数
- } `json:"interact_info"`
- } `json:"note_card"`
- } `json:"items"`
- } `json:"data"`
- } `json:"response_body"`
- } `json:"data"`
- }
- // WeiboPostResponse 微博链接接收结构体
- type WeiboPostResponse struct {
- Code int `json:"code"`
- Msg string `json:"msg"`
- Data struct {
- AttitudesCount int `json:"attitudes_count"` // 点赞数
- CommentsCount int `json:"comments_count"` // 评论数
- RepostsCount int `json:"reposts_count"` // 转发数
- ReadsCount int `json:"reads_count"` // 浏览数
- } `json:"data"`
- }
- // parseNoteStats 小红书接收方法
- func parseNoteStats(jsonData []byte) (likes, comments, collects, shares string, err error) {
- var resp RedBookNoteResponse
- if err := json.Unmarshal(jsonData, &resp); err != nil {
- return "", "", "", "", fmt.Errorf("JSON解析失败: %v", err)
- }
- // 检查数据是否存在
- if len(resp.Data.ResponseBody.Data.Items) == 0 {
- return "", "", "", "", errors.New("未找到笔记数据")
- }
- stats := resp.Data.ResponseBody.Data.Items[0].NoteCard.InteractInfo
- return stats.LikedCount, stats.CommentCount, stats.CollectedCount, stats.ShareCount, nil
- }
- // parseWeiboStats 微博接收方法
- func parseWeiboStats(jsonData []byte) (likes, comments, reposts, reads string, err error) {
- var resp WeiboPostResponse
- // 解析JSON
- if err := json.Unmarshal(jsonData, &resp); err != nil {
- return "", "", "", "", fmt.Errorf("JSON解析失败: %v", err)
- }
- // 检查状态码(微博通常用 code=200 表示成功)
- if resp.Code != 200 {
- return "", "", "", "", fmt.Errorf("API返回错误: %s", resp.Msg)
- }
- // 返回数值(转为字符串,保持与原函数一致)
- return strconv.Itoa(resp.Data.AttitudesCount),
- strconv.Itoa(resp.Data.CommentsCount),
- strconv.Itoa(resp.Data.RepostsCount),
- strconv.Itoa(resp.Data.ReadsCount),
- nil
- }
- // GetRedBookLinkDetail 获取小红书链接数据详情
- func GetRedBookLinkDetail(ctx context.Context, noteId string, xSecToken string) (int, int, int, int, error) {
- url := "http://120.46.92.62:6888/api/xhs/note_detail"
- method := "POST"
- // 构造请求体结构
- requestBody := struct {
- NoteId string `json:"note_id"`
- XSecToken string `json:"xsec_token"`
- ShareText string `json:"share_text"`
- Proxy string `json:"proxy"`
- }{
- NoteId: noteId,
- XSecToken: xSecToken,
- Proxy: "",
- }
- jsonData, err := json.Marshal(requestBody)
- if err != nil {
- fmt.Println("JSON编码失败:", err)
- return 0, 0, 0, 0, err
- }
- payload := strings.NewReader(string(jsonData))
- client := &http.Client{}
- req, err := http.NewRequest(method, url, payload)
- if err != nil {
- // fmt.Println(err)
- return 0, 0, 0, 0, err
- }
- req.Header.Add("Cookie", "abRequestId=87d8ec6f-314f-5914-af1d-21296bf34c5f; a1=197a0b8a06djmry91j6taqhe0kcutwojdcu15nypd50000386246; webId=ae01b40eef7780a778b6624a3b295f4f; gid=yjW08S8Y2yffyjW08DY08SIvKfV6FvjyVK907UfAxd8TSy2879ElV2888qYKJ4K82qfKy82D; webBuild=4.68.0; acw_tc=0a4a2d6e17510033969926232e7b39d55058a43fb37e1ddc19745e6642f746; websectiga=7750c37de43b7be9de8ed9ff8ea0e576519e8cd2157322eb972ecb429a7735d4; sec_poison_id=b4fae566-5d78-4269-85c6-28fc28ec20d3; xsecappid=xhs-pc-web; web_session=040069b22467fb3084e74f796b3a4b11424ee0; loadts=1751003476156; unread={%22ub%22:%22685b56850000000020019eef%22%2C%22ue%22:%22685df405000000002201fd00%22%2C%22uc%22:14}")
- req.Header.Add("Content-Type", "application/json")
- res, err := client.Do(req)
- if err != nil {
- // fmt.Println(err)
- return 0, 0, 0, 0, err
- }
- defer res.Body.Close()
- body, err := ioutil.ReadAll(res.Body)
- if err != nil {
- // fmt.Println(err)
- return 0, 0, 0, 0, err
- }
- fmt.Println(string(body))
- // 提取互动数据
- likes, comments, collects, shares, err := parseNoteStats(body)
- if err != nil {
- //fmt.Println("解析互动数据失败:", err)
- return 0, 0, 0, 0, err
- }
- like, likeErr := strconv.Atoi(likes)
- if likeErr != nil {
- }
- comment, commentErr := strconv.Atoi(comments)
- if commentErr != nil {
- }
- collect, collectErr := strconv.Atoi(collects)
- if collectErr != nil {
- }
- share, shareErr := strconv.Atoi(shares)
- if shareErr != nil {
- }
- return like, comment, collect, share, nil
- }
- // GetWeiBoLinkDetail 获取微博链接数据详情
- func GetWeiBoLinkDetail(ctx context.Context, shareText string) (int, int, int, int, error) {
- url := "http://120.46.92.62:6888/api/weibo/post_detail"
- method := "POST"
- requestBody := struct {
- Id string `json:"id"`
- ShareText string `json:"share_text"`
- Proxy string `json:"proxy"`
- }{
- Id: "",
- ShareText: shareText,
- Proxy: "",
- }
- jsonData, err := json.Marshal(requestBody)
- if err != nil {
- fmt.Println("JSON编码失败:", err)
- return 0, 0, 0, 0, err
- }
- payload := strings.NewReader(string(jsonData))
- client := &http.Client{}
- req, err := http.NewRequest(method, url, payload)
- fmt.Println(req)
- if err != nil {
- //fmt.Println(err)
- return 0, 0, 0, 0, err
- }
- req.Header.Add("Content-Type", "application/json")
- res, err := client.Do(req)
- if err != nil {
- fmt.Println(err)
- return 0, 0, 0, 0, err
- }
- defer res.Body.Close()
- body, err := ioutil.ReadAll(res.Body)
- if err != nil {
- fmt.Println(err)
- return 0, 0, 0, 0, err
- }
- // fmt.Println(string(body))
- likes, comments, collects, shares, err := parseWeiboStats(body)
- if err != nil {
- //fmt.Println("解析互动数据失败:", err)
- return 0, 0, 0, 0, err
- }
- like, likeErr := strconv.Atoi(likes)
- if likeErr != nil {
- }
- comment, commentErr := strconv.Atoi(comments)
- if commentErr != nil {
- }
- collect, collectErr := strconv.Atoi(collects)
- if collectErr != nil {
- }
- share, shareErr := strconv.Atoi(shares)
- if shareErr != nil {
- }
- return like, comment, collect, share, nil
- }
- // WeiboPostsResponse 微博多条数据接收结构体
- type WeiboPostsResponse struct {
- Code int `json:"code"`
- Msg string `json:"msg"`
- Data struct {
- Data struct {
- Cards []struct {
- Mblog struct {
- RetweetedStatus struct {
- Id string `json:"id"`
- Text string `json:"text"`
- CreatedAt string `json:"created_at"`
- AttitudesCount int `json:"attitudes_count"` // 点赞数
- CommentsCount int `json:"comments_count"` // 评论数
- RepostsCount int `json:"reposts_count"` // 转发数
- PendingApproval int `json:"pending_approval"` // 待审数
- PicIds []string `json:"pic_ids"` // 图片ID列表
- PageInfo struct {
- Type string `json:"type"` // 内容类型(video/article)
- PagePic struct {
- Url string `json:"url"` // 封面图URL
- } `json:"page_pic"`
- MediaInfo struct {
- StreamUrl string `json:"stream_url"` // 视频流地址
- } `json:"media_info"`
- } `json:"page_info"`
- } `json:"retweeted_status"`
- } `json:"mblog"`
- } `json:"cards"`
- } `json:"data"`
- } `json:"data"`
- }
- // WeiboPostStats 单条微博的互动数据
- type WeiboPostStats struct {
- Id string `json:"id"`
- CreatedAt string `json:"created_at"`
- Likes int `json:"likes"` // 点赞数
- Comments int `json:"comments"` // 评论数
- Reposts int `json:"reposts"` // 转发数
- HasImages bool `json:"has_images"` // 是否有图片
- HasVideo bool `json:"has_video"` // 是否有视频
- CoverImageUrl string `json:"cover_image_url"` // 封面图URL(视频/文章)
- VideoUrl string `json:"video_url"` // 视频地址(如果有)
- }
- // parseWeiboPosts 解析微博多条数据
- func parseWeiboPosts(body []byte) ([]WeiboPostStats, error) {
- var resp WeiboPostsResponse
- if err := json.Unmarshal(body, &resp); err != nil {
- return nil, fmt.Errorf("JSON解析失败: %v", err)
- }
- if resp.Code != 200 {
- return nil, fmt.Errorf("API返回错误: %s", resp.Msg)
- }
- var posts []WeiboPostStats
- for i, card := range resp.Data.Data.Cards {
- if i >= 5 { // 只取前5条
- break
- }
- mblog := card.Mblog.RetweetedStatus
- hasVideo := mblog.PageInfo.Type == "video"
- posts = append(posts, WeiboPostStats{
- Id: mblog.Id,
- CreatedAt: mblog.CreatedAt,
- Likes: mblog.AttitudesCount,
- Comments: mblog.CommentsCount,
- Reposts: mblog.RepostsCount,
- HasImages: len(mblog.PicIds) > 0,
- HasVideo: hasVideo,
- CoverImageUrl: mblog.PageInfo.PagePic.Url,
- VideoUrl: mblog.PageInfo.MediaInfo.StreamUrl,
- })
- }
- return posts, nil
- }
- // GetWeiBoHistoryList 微博历史作品数据
- func GetWeiBoHistoryList(ctx context.Context, homePageUrl string) ([]WeiboPostStats, error) {
- url := "http://120.46.92.62:6888/api/weibo/user_post" // 替换为实际API地址
- method := "POST"
- requestBody := struct {
- Uid string `json:"uid"`
- ShareText string `json:"share_text"`
- SinceId string `json:"since_id"`
- Proxy string `json:"proxy"`
- }{
- ShareText: homePageUrl,
- Proxy: "",
- }
- client := &http.Client{}
- jsonData, err := json.Marshal(requestBody)
- if err != nil {
- fmt.Println("JSON编码失败:", err)
- return nil, err
- }
- payload := strings.NewReader(string(jsonData))
- req, err := http.NewRequest(method, url, payload)
- if err != nil {
- fmt.Println(err)
- return nil, err
- }
- req.Header.Add("Content-Type", "application/json")
- res, err := client.Do(req)
- if err != nil {
- fmt.Println(err)
- return nil, err
- }
- defer res.Body.Close()
- body, err := ioutil.ReadAll(res.Body)
- if err != nil {
- fmt.Println(err)
- return nil, err
- }
- hisData, hisErr := parseWeiboPosts(body)
- if hisErr != nil {
- fmt.Println(hisErr)
- }
- return hisData, nil
- }
- // RedBookPostsResponse 小红书多条数据接收结构体
- type RedBookPostsResponse struct {
- Code int `json:"code"`
- Msg string `json:"msg"`
- Data struct {
- ResponseBody struct {
- Data struct {
- Note []struct {
- NoteId string `json:"note_id"`
- XsecToken string `json:"xsec_token"`
- } `json:"notes"`
- } `json:"data"`
- } `json:"response_body"`
- } `json:"data"`
- }
- func parseRedBookPosts(body []byte) ([]string, []string, error) {
- var resp RedBookPostsResponse
- if err := json.Unmarshal(body, &resp); err != nil {
- return nil, nil, fmt.Errorf("JSON解析失败: %v", err)
- }
- if resp.Code != 200 {
- return nil, nil, fmt.Errorf("API返回错误: %s", resp.Msg)
- }
- var linkList []string
- var secTokenList []string
- for i, card := range resp.Data.ResponseBody.Data.Note {
- if i >= 5 { // 只取前5条
- break
- }
- linkList = append(linkList, card.NoteId)
- secTokenList = append(secTokenList, card.XsecToken)
- }
- return linkList, secTokenList, nil
- }
- // GetRedBookHistoryList 小红书历史作品列表
- func GetRedBookHistoryList(ctx context.Context, homePageUrl string) ([]RedBookNoteResponse, error) {
- url := "http://120.46.92.62:6888/api/xhs/user_post"
- method := "POST"
- requestBody := struct {
- UserId string `json:"user_id"`
- Cursor string `json:"cursor"`
- Proxy string `json:"proxy"`
- }{
- UserId: homePageUrl,
- Proxy: "",
- }
- client := &http.Client{}
- jsonData, err := json.Marshal(requestBody)
- if err != nil {
- fmt.Println("JSON编码失败:", err)
- return nil, err
- }
- payload := strings.NewReader(string(jsonData))
- req, err := http.NewRequest(method, url, payload)
- if err != nil {
- fmt.Println(err)
- return nil, err
- }
- req.Header.Add("Cookie", "abRequestId=023e90e1-a95a-58db-830a-d66c0cc67f60; a1=19566f0f66eglh42hy8peqvpak3xqglp49289p8xb50000109075; webId=d189df044ca380c74b5b97bc300db5a1; gid=yj2KKiyyyY4Yyj2KKi8iKjUYKdk1x4JxvYUdJCDAhU0TqY28CAk1Uj888y8j8W288q4Jif4i; acw_tc=0a4a949617517192833111453ec142bc6ab7f9b09590524b2d59d413f0ffb7; websectiga=a9bdcaed0af874f3a1431e94fbea410e8f738542fbb02df1e8e30c29ef3d91ac; sec_poison_id=9bc0c279-b964-4448-87df-d08559819919; web_session=0400698c340cec15e62be2555c3a4b29a1365a; xsecappid=xhs-pc-web; webBuild=4.71.0; loadts=1751719579486; unread={%22ub%22:%22685be6260000000015023bc6%22%2C%22ue%22:%2268617298000000001c0337aa%22%2C%22uc%22:23}")
- req.Header.Add("Content-Type", "application/json")
- res, err := client.Do(req)
- if err != nil {
- fmt.Println(err)
- return nil, err
- }
- defer res.Body.Close()
- body, err := ioutil.ReadAll(res.Body)
- if err != nil {
- fmt.Println(err)
- return nil, err
- }
- linkList, tokenList, linkErr := parseRedBookPosts(body)
- if linkErr != nil {
- return nil, linkErr
- }
- if linkList != nil {
- fmt.Println(linkList)
- fmt.Println(GetRedBookLinkDetail(ctx, linkList[2], tokenList[2]))
- }
- return nil, nil
- }
|