diff --git a/src/clis/xiaohongshu/comments.yaml b/src/clis/xiaohongshu/comments.yaml new file mode 100644 index 0000000..cf33003 --- /dev/null +++ b/src/clis/xiaohongshu/comments.yaml @@ -0,0 +1,35 @@ +site: xiaohongshu +name: comments +description: "小红书笔记评论" +domain: www.xiaohongshu.com +strategy: intercept +browser: true + +args: + id: + type: str + required: true + description: Note ID + limit: + type: int + default: 20 + description: Number of comments + +columns: [rank, author, content, likes, time] + +pipeline: + - navigate: https://www.xiaohongshu.com/explore/${{ args.id }} + - wait: 3 + - tap: + store: comment + action: fetchComments + capture: comment/list + select: data.comments + timeout: 8 + - map: + rank: ${{ index + 1 }} + author: ${{ item.user_info.nickname }} + content: ${{ item.content }} + likes: ${{ item.like_count }} + time: ${{ item.create_time }} + - limit: ${{ args.limit | default(20) }} diff --git a/src/clis/xiaohongshu/me.yaml b/src/clis/xiaohongshu/me.yaml new file mode 100644 index 0000000..c7fd3f4 --- /dev/null +++ b/src/clis/xiaohongshu/me.yaml @@ -0,0 +1,35 @@ +site: xiaohongshu +name: me +description: "我的小红书个人信息" +domain: www.xiaohongshu.com +strategy: intercept +browser: true + +columns: [nickname, red_id, fans, follows, notes, likes_collected] + +pipeline: + - navigate: https://www.xiaohongshu.com/user/profile/self + - wait: 3 + - tap: + store: user + action: fetchSelfProfile + capture: user/selfprofile + timeout: 8 + - evaluate: | + (() => { + const app = document.querySelector('#app')?.__vue_app__; + const pinia = app?.config?.globalProperties?.$pinia; + if (!pinia?._s) return { error: 'Page not ready' }; + const userStore = pinia._s.get('user'); + if (!userStore) return { error: 'User store not found' }; + const state = userStore.$state || {}; + const u = state.selfInfo || state.currentUserInfo || state.userInfo || {}; + return [{ + nickname: u.nickname || u.name || '', + red_id: u.red_id || u.redId || '', + fans: u.fans || u.fansCount || 0, + follows: u.follows || u.followsCount || 0, + notes: u.notes || u.noteCount || 0, + likes_collected: u.collected || u.likedAndCollected || 0, + }]; + })() diff --git a/src/clis/xiaohongshu/note.yaml b/src/clis/xiaohongshu/note.yaml new file mode 100644 index 0000000..21bb598 --- /dev/null +++ b/src/clis/xiaohongshu/note.yaml @@ -0,0 +1,45 @@ +site: xiaohongshu +name: note +description: "小红书笔记详情" +domain: www.xiaohongshu.com +strategy: intercept +browser: true + +args: + id: + type: str + required: true + description: Note ID + +columns: [title, author, likes, collects, comments, type, time, desc] + +pipeline: + - navigate: https://www.xiaohongshu.com/explore/${{ args.id }} + - wait: 3 + - tap: + store: note + action: fetchNoteData + capture: v1/note/feed + timeout: 8 + - evaluate: | + (() => { + const app = document.querySelector('#app')?.__vue_app__; + const pinia = app?.config?.globalProperties?.$pinia; + if (!pinia?._s) return { error: 'Page not ready' }; + const noteStore = pinia._s.get('note'); + if (!noteStore) return { error: 'Note store not found' }; + const state = noteStore.$state || {}; + const notes = state.noteMap || state.noteDetailMap || {}; + const n = Object.values(notes)[0] || {}; + const nc = n.noteCard || n.note_card || n; + return [{ + title: nc.title || nc.displayTitle || nc.display_title || '', + author: nc.user?.nickname || nc.user?.name || '', + likes: nc.interactInfo?.likedCount || nc.interact_info?.liked_count || 0, + collects: nc.interactInfo?.collectedCount || nc.interact_info?.collected_count || 0, + comments: nc.interactInfo?.commentCount || nc.interact_info?.comment_count || 0, + type: nc.type || '', + time: nc.time ? new Date(nc.time).toISOString().slice(0, 10) : (nc.createTime || ''), + desc: (nc.desc || '').slice(0, 200), + }]; + })() diff --git a/src/clis/xiaohongshu/user-posts.yaml b/src/clis/xiaohongshu/user-posts.yaml new file mode 100644 index 0000000..702e2d3 --- /dev/null +++ b/src/clis/xiaohongshu/user-posts.yaml @@ -0,0 +1,35 @@ +site: xiaohongshu +name: user-posts +description: "小红书用户的所有笔记" +domain: www.xiaohongshu.com +strategy: intercept +browser: true + +args: + uid: + type: str + required: true + description: User UID + limit: + type: int + default: 20 + description: Number of posts + +columns: [rank, title, likes, type, url] + +pipeline: + - navigate: https://www.xiaohongshu.com/user/profile/${{ args.uid }} + - wait: 3 + - tap: + store: user + action: fetchUserNotes + capture: user/posted + select: data.notes + timeout: 8 + - map: + rank: ${{ index + 1 }} + title: ${{ item.display_title }} + likes: ${{ item.interact_info.liked_count }} + type: ${{ item.type }} + url: https://www.xiaohongshu.com/explore/${{ item.note_id }} + - limit: ${{ args.limit | default(20) }}