Skill: mrmao007/rednote-skills (version 1.0.0)

--- name: rednote-skill description: Comprehensive tool for interacting with rednote (xiaohongshu,小红书) platform. This skill enables users to search for posts by keyword, extract content from specific notes in markdown format, and perform interaction actions like liking, commenting, collecting, following, and publishing. Use this when users need to engage with content from xiaohongshu.com. --- # Rednote Skill This skill allows you to fully interact with the Xiaohongshu (Little Red Book) platform. You can search for posts by keyword and return results, extract content from specific notes to structured markdown format, and perform engagement actions like liking, commenting, collecting, following users, and more. ## Configuration and Preparation ### Requirements - Python 3.7+ - Playwright (install with `pip install playwright`) - Playwright drivers (install with `playwright install`) - Configured browser environment ### Always DO FIRST Before using this skill, the system will verify your login status: ``` python scripts/validate_cookies.py ``` If the output is `True`, you have normal access and can proceed with search operations. If the output is `False` or the login button is visible, the system will automatically execute the manual login procedure: ``` python scripts/manual_login.py ``` The system will launch the login interface in a browser window. You'll need to follow the instructions in the opened browser to complete the login process manually, then close the browser after completion. ## Usage Steps ### 1. Environment Setup Before using this skill, ensure that: 1. The required dependencies are installed (Python 3.7+, Playwright) 2. The system will automatically handle the cookie saving via the manual login process when needed 3. Login status will be validated automatically using the validation utility ### 2. Using Search Functions The skill provides several search and extraction functions: - **Search Notes by Keyword**: `python scripts/search_note_by_key_word.py <KEYWORD> [--top_n TOP_N]` - **Extract Note Content**: `python scripts/dump_note.py <NOTE_URL>` ### 3. Using Interaction Functions The skill provides several interaction functions: - **Like Note**: `python scripts/like_note.py <NOTE_URL>` - **Collect Note**: `python scripts/collect_note.py <NOTE_URL>` - **Comment on Note**: `python scripts/comment_note.py <NOTE_URL> <COMMENT_TEXT>` - **Follow User**: `python scripts/follow_user.py <NOTE_URL>` - **Publish Note**: `python scripts/publish_note.py --image-urls <IMG1 [IMG2 ...]> --title <TITLE> --content <CONTENT> --tags <TAG1 [TAG2 ...]>` - **Validate Login**: `python scripts/validate_cookies.py` - **Manual Login**: `python scripts/manual_login.py` ### 4. Complete Workflow 1. Validate login status before starting interactions 2. Execute desired search functions if you need to find specific notes 3. Execute desired interaction functions with proper arguments 4. Monitor results for successful completion ## Function Descriptions This skill provides the following functions for searching content on and interacting with the Xiaohongshu platform: ### Search Notes (`search_note_by_key_word.py`) **Purpose**: Searches for Xiaohongshu notes using the provided keyword. **Parameters**: - `keyword` (string): The keyword to search for - `--top_n` (integer, optional): Number of return notes (default is 5) **Returns**: List of note URLs that match the keyword **Behavior**: Launches browser, searches for the keyword on Xiaohongshu, returns matching note URLs. ### Extract Note Content (`dump_note.py`) **Purpose**: Extracts specific note content and converts to formatted markdown. **Parameters**: - `note_url` (string): The URL of the note to extract content from **Returns**: Structured markdown content including author, title, media, description, tags, and interaction data **Behavior**: Launches browser, accesses the note, extracts content and formats to markdown. ### Like Note (`like_note.py`) **Purpose**: Likes a specific note on Xiaohongshu using the note URL. **Parameters**: - `note_url` (string): The URL of the note to like **Returns**: Success or error message indicating if the like was successful **Behavior**: Launches browser, navigates to the note URL, clicks the like button, then closes the browser. ### Collect Note (`collect_note.py`) **Purpose**: Collects (saves) a specific note to the user's collection. **Parameters**: - `note_url` (string): The URL of the note to collect **Returns**: Success or error message indicating if the collection was successful **Behavior**: Launches browser, navigates to the note URL, clicks the collect button, then closes the browser. ### Comment on Note (`comment_note.py`) **Purpose**: Adds a comment to a specific note on Xiaohongshu. **Parameters**: - `note_url` (string): The URL of the note to comment on - `comment_text` (string): The text content of the comment **Returns**: Success or error message indicating if the comment was published **Behavior**: Launches browser, navigates to the note URL, fills in the comment text, clicks the send button, then closes the browser. ### Follow User (`follow_user.py`) **Purpose**: Follows the user who created a specific note by visiting a note URL. **Parameters**: - `note_url` (string): The URL of a note by the user to follow **Returns**: Success or error message indicating if the follow action was successful **Behavior**: Launches browser, navigates to the note URL, clicks the follow button if available, then closes the browser. ### Validate Login Status (`validate_cookies.py`) **Purpose**: Checks if the saved authentication tokens are valid and the user is logged in to Xiaohongshu. **Parameters**: None **Returns**: Boolean value indicating whether login is successful **Behavior**: Launches browser, accesses Xiaohongshu homepage with stored credentials, checks for login state. ### Manual Login (`manual_login.py`) **Purpose**: Assists in creating valid authentication cookies by opening the login interface. **Parameters**: None **Returns**: Success or error message after cookies are saved **Behavior**: Launches browser, navigates to Xiaohongshu, allows user to log in manually, then saves cookies to storage file. ### Publish Note (`publish_note.py`) **Purpose**: Publishes a new image-text note to the user's Xiaohongshu account with provided content, images, and tags. **Parameters**: - `--image-urls IMG1 [IMG2 ...]`: Paths to one or more image files to upload with the note (required) - `--title TITLE`: The title for the new note (required) - `--content CONTENT`: The main content text for the new note (required) - `--tags TAG1 [TAG2 ...]`: One or more tags to attach to the note (required) **Returns**: Success or error message indicating if the note was published successfully **Behavior**: Launches browser, navigates to the Xiaohongshu publish page, fills in the note title, content, tags and uploads provided images, then clicks the publish button. ## Examples ### Basic Search and Content Extraction ``` # Validate login status python scripts/validate_cookies.py # Search for notes about "旅行攻略" python scripts/search_note_by_key_word.py "旅行攻略" --top_n 3 # Extract content from a specific note python scripts/dump_note.py "https://www.xiaohongshu.com/explore/some-note-id" ``` ### Basic Liking and Collecting ``` # Like a specific note python scripts/like_note.py "https://www.xiaohongshu.com/explore/some-note-id" # Collect a specific note python scripts/collect_note.py "https://www.xiaohongshu.com/explore/some-note-id" ``` ### Commenting on a Note ``` # Add a comment to a specific note python scripts/comment_note.py "https://www.xiaohongshu.com/explore/some-note-id" "Beautiful content! Thanks for sharing." ``` ### Following a User ``` # Follow a user based on one of their posts python scripts/follow_user.py "https://www.xiaohongshu.com/explore/some-note-by-user-id" ``` ### Publishing a Note ``` # Publish a new note with images, title, content, and tags python scripts/publish_note.py \ --image-urls "/path/to/img1.jpg" "/path/to/img2.jpg" \ --title "My New Post" \ --content "Check out this amazing discovery!" \ --tags "travel" "food" "lifestyle" ``` ### Complete User Session ``` # 1. Validate login python scripts/validate_cookies.py # 2. Search for interesting content python scripts/search_note_by_key_word.py "美食推荐" --top_n 5 # 3. Extract detailed content from a note python scripts/dump_note.py "https://www.xiaohongshu.com/explore/note1" # 4. Like interesting content python scripts/like_note.py "https://www.xiaohongshu.com/explore/note1" # 5. Collect useful content python scripts/collect_note.py "https://www.xiaohongshu.com/explore/note2" # 6. Engage with community python scripts/comment_note.py "https://www.xiaohongshu.com/explore/note3" "Awesome tutorial!" # 7. Follow good content creators python scripts/follow_user.py "https://www.xiaohongshu.com/explore/note-by-creator" ``` ## Implementation Guidelines ### Best Practices 1. **Validate Login First**: Login status will be automatically checked using `validate_cookies.py` before performing any interactions to ensure smooth operations. 2. **Rate Limiting**: To avoid account restrictions, implement appropriate delays between consecutive interactions. Avoid excessive rapid interactions. 3. **Error Handling**: Check the return values from the functions to ensure operations were successful before proceeding to the next action. 4. **User Intent**: Only engage with content that matches user interest and preferences. The skill should complement user decisions. 5. **Browser State Management**: The scripts manage browser opening and closing, so ensure system resources are available for these operations. ### Integration Considerations 1. **Session Management**: The skill maintains session state through cookies stored in `rednote_cookies.json`. Ensure this file is properly secured. 2. **Browser Automation**: The skill uses headless browsers for automation. Ensure the system has a compatible browser environment set up. 3. **URL Format**: The scripts expect properly formatted Xiaohongshu URLs. Ensure URLs are valid before passing to functions. 4. **Content Appropriateness**: Integrate this skill in a way that ensures interactions are appropriate and align with platform terms of service. ## Configuration and Preparation ### Advanced Setup #### Cookie Management - The skill stores authentication data in `rednote_cookies.json` - This file is created automatically during the manual login process - For security, protect this cookie file from unauthorized access #### Environment Variables - No specific environment variables are required - The skill uses the default configuration files in the scripts directory ### Prerequisites Verification Before using the rednote skill, verify: 1. **System Setup**: - Python 3.7 or above - Playwright installed (`pip install playwright`) - Browser drivers installed (`playwright install`) - Minimum available disk space for browser operation 2. **Xiaohongshu Access**: - Ability to access Xiaohongshu.com from your network - Compliance with Xiaohongshu's terms of service - Valid Xiaohongshu account credentials 3. **Security Setup**: - The system will handle automatic login when needed - Login status will be confirmed via validation script - Secured storage for authentication tokens ## Troubleshooting ### Common Issues #### Login Error (`❌ 未找到 cookies 文件，请先登录小红书并保存 cookies`) **Cause**: The `rednote_cookies.json` file doesn't exist or is not in the correct location. **Solution**: The system will automatically execute `python scripts/manual_login.py` to perform manual login and save cookies. The user just needs to complete the login process in the opened browser window. #### Login Session Expired (`❌ 未登录小红书，请先登录`) **Cause**: Authentication tokens have expired or are invalid. **Solution**: The system will re-verify login status and may execute `python scripts/manual_login.py` again to refresh tokens. The user just needs to complete the login process in the opened browser window if prompted. #### Page Navigation Issues **Cause**: Network connectivity issues or URL format errors. **Solution**: Verify URL format is correct, ensure internet connection is stable, and check if Xiaohongshu is accessible. #### Element Not Found During Interaction **Cause**: Xiaohongshu's UI might have changed or the page hasn't loaded completely. **Solution**: Retry the operation; if the issue persists, check for interface changes or wait before trying again. ### Debugging Steps 1. **Verify Prerequisites**: Ensure all requirements are installed and accessible 2. **Check Login Status**: Run the validation script before operations 3. **Review URL Format**: Ensure URLs are properly formatted Xiaohongshu links 4. **Monitor Browser Behavior**: Use non-headless mode to observe the automation process 5. **Check Storage Files**: Verify cookies file exists and is accessible ### Performance Considerations - Browser automation is resource-intensive; ensure system has sufficient memory and CPU - Network latency may affect operation timing; consider adding delays between operations - Run validation scripts periodically to confirm stable authentication ## Limitations and Considerations ### Platform Limitations - **Terms of Service**: This skill must be used in compliance with Xiaohongshu's terms of service and community guidelines - **Rate Limiting**: Xiaohongshu may impose limits on the number of interactions per time period - **UI Changes**: Xiaohongshu may update their interface, which could break element selectors used by the skill - **Geographic Restrictions**: Some functionality may be limited based on geographic location ### Technical Limitations - **Browser Dependence**: The skill relies on browser automation which may be slower than direct API calls - **Stability**: Browser automation can be affected by network conditions and site changes - **Resource Usage**: Each interaction launches a browser instance, consuming system resources - **Headless Compatibility**: Some interactions may work better in non-headless mode ### Security Considerations - **Authentication Storage**: Authentication credentials are stored in `rednote_cookies.json` and should be secured - **Privacy**: Interactions performed with this skill will be visible to other users on Xiaohongshu - **Data Handling**: The skill doesn't collect user data beyond session management for interaction ### Ethical Considerations - **Authentic Engagement**: Use the skill to facilitate genuine engagement with content that users actually find interesting - **Respect Content Creators**: Consider the impact of interactions on content creators and their audience - **Anti-Spam Ethics**: Avoid using the skill for spam-like behavior or in ways that could harm the platform ecosystem

path: scripts/dump_note.py
content: import argparse
import json
import re
from playwright.sync_api import sync_playwright
import asyncio
from datetime import datetime

def dump_note(note_url: str) -> str:
    """
    导出小红书笔记内容
    """
    with sync_playwright() as playwright:
        browser = playwright.chromium.launch(headless=True)
        try: 
            context = browser.new_context(storage_state="rednote_cookies.json")
        except FileNotFoundError:
            return "❌ 未找到 cookies 文件，请先登录小红书并保存 cookies"
        page = context.new_page()
        page.goto(note_url)
        print("🌐 导航到小红书笔记页面...")
        page.wait_for_timeout(1000)
        login_button = page.locator("form").get_by_role("button", name="登录")
        if(login_button.is_visible()):
            return "❌ 未登录小红书，请先登录"
        
        # 直接在浏览器端提取 note 字段
        note_data = page.evaluate("""
            () => {
                const noteDetailMap = window.__INITIAL_STATE__?.note?.noteDetailMap;
                if (noteDetailMap) {
                    const firstKey = Object.keys(noteDetailMap)[0];
                    return JSON.stringify(noteDetailMap[firstKey]?.note);
                }
                return null;
            }
        """)
        json_data = json.loads(note_data)
        markdown_content = generate_rednote_markdown(json_data)

        context.close()
        browser.close()
            
        return markdown_content
    
def generate_rednote_markdown(json_data):
    # 提取数据
    note_type = json_data['type']
    title = json_data['title']
    desc = json_data['desc']
    nickname = json_data['user']['nickname']
    avatar = json_data['user']['avatar']
    tags = [tag['name'] for tag in json_data['tagList']]
    liked_count = json_data['interactInfo']['likedCount']
    collected_count = json_data['interactInfo']['collectedCount']
    comment_count = json_data['interactInfo']['commentCount']
    share_count = json_data['interactInfo']['shareCount']
    create_time = datetime.fromtimestamp(json_data['time']/1000)
    update_time = datetime.fromtimestamp(json_data['lastUpdateTime']/1000)
    images = [image['urlDefault'] for image in json_data['imageList']] if 'imageList' in json_data else []
    video_url = json_data['video']['media']['stream']['h264'][0]['masterUrl'] if 'video' in json_data else None
    ip_location = json_data.get('ipLocation', '')
    
    # 生成 Markdown
    markdown = f"""# {title}

<div align="center">
<img src="{avatar}" width="50" style="border-radius: 50%;" />

**{nickname}**
</div>

"""
    
    # 添加媒体内容
    if note_type == "video" and video_url:
        markdown += f"""## 🎬 视频

<div style="position: relative; width: 100%; padding-top: 56.25%;">
    <iframe 
        src="{video_url}" 
        style="position: absolute; top: 0; left: 0; width: 100%; height: 100%;"
        scrolling="no" 
        border="0" 
        frameborder="no" 
        allowfullscreen="true">
    </iframe>
</div>

""" 
    if note_type == "normal" and images:
        markdown += """## 🖼️ 图片

"""
        for idx, img_url in enumerate(images, 1):
            markdown += f"![图片{idx}]({img_url})\n\n"
    
    # 添加互动数据
    markdown += f"""

## 📝 正文

{desc}

## 🏷️ 标签

{' '.join([f'`#{tag}`' for tag in tags])}

## 📊 互动数据

| 👍 点赞 | ⭐ 收藏 | 💬 评论 | 🔗 分享 |
|:---:|:---:|:---:|:---:|
| {liked_count} | {collected_count} | {comment_count} | {share_count} |

## ℹ️ 其他信息

- **发布时间**：{create_time.strftime('%Y-%m-%d %H:%M:%S')}
- **更新时间**：{update_time.strftime('%Y-%m-%d %H:%M:%S')}
- **IP 属地**：{ip_location}
- **内容类型**：{'📹 视频' if note_type == 'video' else '📷 图文'}
"""
    
    return markdown

if __name__ == "__main__":
    
    parser = argparse.ArgumentParser(description="导出小红书笔记内容")
    parser.add_argument("note_url", type=str, help="小红书笔记URL")
    args = parser.parse_args()
    note_url = args.note_url
    
    result = dump_note(note_url)
    print(result)

path: scripts/search_note_by_key_word.py
content: from html import parser
from playwright.sync_api import sync_playwright
import argparse


def search(key_word: str, top_n: int) -> list[str]:
    """
    搜索小红书笔记
    """
    with sync_playwright() as playwright:
        browser =playwright.chromium.launch(headless=True)
        try: 
            context = browser.new_context(storage_state="rednote_cookies.json")
        except FileNotFoundError:
            return ["❌ 未找到 cookies 文件，请先登录小红书并保存 cookies"]
        page = context.new_page()
        page.goto("https://www.xiaohongshu.com/search_result?keyword=" + key_word)
        print("🌐 导航到小红书主页...")
        page.wait_for_timeout(3000)
        login_button = page.locator("form").get_by_role("button", name="登录")
        if(login_button.is_visible()):
            return ["❌ 未登录小红书，请先登录"]
        
        prefix = 'https://www.xiaohongshu.com'
        links = page.query_selector_all('a.cover.mask.ld')
        # 获取所有 href 属性
        hrefs = []
        for link in links:
            href = link.get_attribute('href')
            if href:
                href = prefix + href
                hrefs.append(href)
            if len(hrefs) >= top_n:
                break


        context.close()
        browser.close()
            
        return hrefs
            
        

if __name__ == "__main__":
    
    parser = argparse.ArgumentParser(description="搜索小红书笔记")
    parser.add_argument("keyword", type=str, help="搜索关键词")
    parser.add_argument("--top_n", type=int, default=5, help="返回的笔记数量")
    args = parser.parse_args()
    key_word = args.keyword
    top_n = args.top_n
    
    result = search(key_word, top_n)
    print(result)

path: scripts/manual_login.py
content: 
from playwright.sync_api import sync_playwright

def save_cookies(context):
    """异步保存cookies到文件"""
    try:
        print("🍪 获取cookies...")
        cookies_file = "rednote_cookies.json"
        storage_state = context.storage_state(path=cookies_file)
        
        print(f"✅ Cookies已保存到: {cookies_file}")
        print(f"📊 共保存了 {len(storage_state)} 个cookies")
    except Exception as e:
        print(f"保存cookies结束")

def manual_login() -> str:
    with sync_playwright() as playwright:
        browser = playwright.chromium.launch(headless=False)
        context = browser.new_context()
        
        # 监听context关闭事件
        context.on("close", lambda: save_cookies(context)) # type: ignore
        
        page = context.new_page()
        print("🌐 导航到小红书登录页面...")
        page.goto("https://www.xiaohongshu.com/explore")
        
        print("\n📋 请按照以下步骤操作:")
        print("1. 在浏览器中手动登录小红书")
        print("2. 登录成功后，确保可以正常访问小红书内容")
        print("3. 完成后，关闭浏览器...")
        
        try:
            # 无限等待，直到页面被关闭
            page.wait_for_event("close", timeout=0)
        except Exception as e:
            print(f"等待过程中断: {e}")
        finally:
            save_cookies(context)
            browser.close()
        
        return "✅ 登录流程完成，Cookies已保存"

if __name__ == "__main__":
    result = manual_login()
    print(result)

path: scripts/publish_note.py
content: import argparse
import re
from typing import List
from playwright.sync_api import sync_playwright

class RednoteArticle:
    def __init__(self, title: str, content: str, tags: List[str], image_urls: List[str]):
        self.title = title
        self.content = content
        self.tags = tags
        self.image_urls = image_urls

    def __str__(self):
        return f"标题: {self.title}, 内容: {self.content}, 标签: {', '.join(self.tags)}, 图片: {', '.join(self.image_urls)}"

    def __repr__(self):
        return self.__str__()


def publish_text(image_urls: List[str], title: str, content: str, tags: List[str]) -> str:
    """
    发布小红书图文笔记
    :param image_urls: 图片URL列表
    :param title: 笔记标题
    :param content: 笔记内容
    :param tags: 标签列表
    """
    rednoteArticle = RednoteArticle(title, content, tags, image_urls)
    
    with sync_playwright() as playwright:
        browser = playwright.chromium.launch(headless=False)
        try: 
            context = browser.new_context(storage_state="rednote_cookies.json")
        except FileNotFoundError:
            return "❌ 未找到 cookies 文件，请先登录小红书并保存 cookies"
        page = context.new_page()
        page.goto("https://www.xiaohongshu.com/explore")
        print("🌐 导航到小红书主页...")
        page.wait_for_timeout(10000)
        login_button = page.locator("form").get_by_role("button", name="登录")
        if(login_button.is_visible()):
            return "❌ 未登录小红书，请先登录"
        
        page.get_by_role("button", name="创作中心").hover()
        with page.expect_popup() as page1_info:
            page.get_by_role("link", name="创作服务").click()
            
        page1 = page1_info.value
        print("🕒 等待页面跳转")
        
        page1.get_by_text("发布图文笔记").click()
    
        
        print("🖼️ 上传图片...")
        page1.on("filechooser", lambda file_chooser: file_chooser.set_files(rednoteArticle.image_urls)) # 替换为你的文件路径
        
        page1.get_by_role("textbox", name="填写标题会有更多赞哦").fill(rednoteArticle.title)
        final_content = rednoteArticle.content + "\n\n" + "\n".join([f"#{tag}" for tag in rednoteArticle.tags])
        page1.get_by_role("paragraph").filter(has_text=re.compile(r"^$")).fill(final_content)
        page1.wait_for_timeout(10000) # 等待发布内容加载完成
        page1.get_by_role("button", name="发布").click()
        print("🕒 等待发布成功")
        page1.wait_for_timeout(5000) # 等待发布完成
        print("✅ 发布成功")
        
        # ---------------------
        context.close()
        browser.close()
        
        return "✅ 笔记发布成功"

if __name__ == "__main__":
    
    parser = argparse.ArgumentParser(description="发布小红书图文笔记")
    parser.add_argument("--image-urls", nargs="+", type=str, required=True, help="图片URL列表")
    parser.add_argument("--title", type=str, required=True, help="笔记标题")
    parser.add_argument("--content", type=str, required=True, help="笔记内容")
    parser.add_argument("--tags", nargs="+", type=str, required=True, help="标签列表")
    args = parser.parse_args()
    
    result = publish_text(args.image_urls, args.title, args.content, args.tags)
    print(result)

path: scripts/validate_cookies.py
content: from playwright.sync_api import sync_playwright


def validate_cookies() -> bool:
    """验证保存的cookies是否有效"""
    with sync_playwright() as playwright:
        browser =playwright.chromium.launch(headless=False)
        try: 
            context = browser.new_context(storage_state="rednote_cookies.json")
        except FileNotFoundError:
            return False
        page = context.new_page()
        page.goto("https://www.xiaohongshu.com/explore")
        
        # 检查是否登录成功
        login_button = page.locator("form").get_by_role("button", name="登录")
        is_login = not login_button.is_visible()
        
        context.close()
        browser.close()
        
        return is_login

if __name__ == "__main__":
    result = validate_cookies()
    print(result) 

path: scripts/comment_note.py
content: import argparse
from playwright.sync_api import sync_playwright

def comment_note(note_url: str, comment_text: str) -> str:
    """
    评论小红书笔记
    :param note_url: 笔记URL
    :param comment_text: 评论内容
    """
    with sync_playwright() as playwright:
        browser = playwright.chromium.launch(headless=False)
        try: 
            context = browser.new_context(storage_state="rednote_cookies.json")
        except FileNotFoundError:
            return "❌ 未找到 cookies 文件，请先登录小红书并保存 cookies"
        page = context.new_page()
        page.goto(note_url)
        print("🌐 导航到小红书笔记页面...")
        page.wait_for_timeout(1000)
        login_button = page.locator("form").get_by_role("button", name="登录")
        if(login_button.is_visible()):
            return "❌ 未登录小红书，请先登录"
        
        page.locator(".chat-wrapper > .reds-icon").click()
        page.locator("#content-textarea").fill(comment_text)
        page.get_by_role("button", name="发送").click()
        
        context.close()
        browser.close()
            
        return "💬 评论已发布"

if __name__ == "__main__":
    
    parser = argparse.ArgumentParser(description="评论小红书笔记")
    parser.add_argument("note_url", type=str, help="小红书笔记URL")
    parser.add_argument("comment_text", type=str, help="评论内容")
    args = parser.parse_args()
    note_url = args.note_url
    comment_text = args.comment_text
    
    result = comment_note(note_url, comment_text)
    print(result)

path: scripts/follow_user.py
content: import argparse
from playwright.sync_api import sync_playwright

def follow_user(note_url: str) -> str:
    """
    关注小红书用户
    :param note_url: 笔记URL
    """
    with sync_playwright() as playwright:
        browser = playwright.chromium.launch(headless=False)
        try: 
            context = browser.new_context(storage_state="rednote_cookies.json")
        except FileNotFoundError:
            return "❌ 未找到 cookies 文件，请先登录小红书并保存 cookies"
        page = context.new_page()
        page.goto(note_url)
        print("🌐 导航到小红书笔记页面...")
        page.wait_for_timeout(1000)
        login_button = page.locator("form").get_by_role("button", name="登录")
        if(login_button.is_visible()):
            return "❌ 未登录小红书，请先登录"
        
        result = "👤 用户已关注"
        try:
            page.get_by_role("button", name="关注").click()
        except Exception as e:
            result = "⚠️ 已经关注该用户或无法关注"
            
        context.close()
        browser.close()

        return result

if __name__ == "__main__":
    
    parser = argparse.ArgumentParser(description="关注小红书用户")
    parser.add_argument("note_url", type=str, help="小红书笔记URL")
    args = parser.parse_args()
    note_url = args.note_url
    
    result = follow_user(note_url)
    print(result)

path: scripts/like_note.py
content: import argparse
from playwright.sync_api import sync_playwright

def like_note(note_url: str) -> str:
    """
    点赞小红书笔记
    :param note_url: 笔记URL
    """
    with sync_playwright() as playwright:
        browser = playwright.chromium.launch(headless=False)
        try: 
            context = browser.new_context(storage_state="rednote_cookies.json")
        except FileNotFoundError:
            return "❌ 未找到 cookies 文件，请先登录小红书并保存 cookies"
        page = context.new_page()
        page.goto(note_url)
        print("🌐 导航到小红书笔记页面...")
        page.wait_for_timeout(1000)
        login_button = page.locator("form").get_by_role("button", name="登录")
        if(login_button.is_visible()):
            return "❌ 未登录小红书，请先登录"
        
        page.locator(".left > .like-wrapper > .like-lottie").click()

        context.close()
        browser.close()
            
        return "❤️ 笔记已点赞"

if __name__ == "__main__":
    
    parser = argparse.ArgumentParser(description="点赞小红书笔记")
    parser.add_argument("note_url", type=str, help="小红书笔记URL")
    args = parser.parse_args()
    note_url = args.note_url
    
    result = like_note(note_url)
    print(result)

path: scripts/collect_note.py
content: import argparse
from playwright.sync_api import sync_playwright

def collect_note(note_url: str) -> str:
    """
    收藏小红书笔记
    :param note_url: 笔记URL
    """
    with sync_playwright() as playwright:
        browser = playwright.chromium.launch(headless=False)
        context = browser.new_context(storage_state="rednote_cookies.json")
        page = context.new_page()
        page.goto(note_url)
        print("🌐 导航到小红书笔记页面...")
        page.wait_for_timeout(1000)
        login_button = page.locator("form").get_by_role("button", name="登录")
        if(login_button.is_visible()):
            return "❌ 未登录小红书，请先登录"
        
        page.locator(".reds-icon.collect-icon").click()

        context.close()
        browser.close()
            
        return "📥 笔记已收藏"

if __name__ == "__main__":
    
    parser = argparse.ArgumentParser(description="收藏小红书笔记")
    parser.add_argument("note_url", type=str, help="小红书笔记URL")
    args = parser.parse_args()
    note_url = args.note_url
    
    result = collect_note(note_url)
    print(result)

Security scan verdicts — ClawScan: suspicious | static analysis: clean | VirusTotal: suspicious | SkillSpector: suspicious (CRITICAL)