小红书矩阵系统开发:私域流量转化与管理完整技术实现

小红书矩阵系统私域流量转化与管理方案

矩阵系统开发是当前社交媒体运营领域的技术热点,随着小红书平台用户规模的持续增长和商业价值的不断提升,越来越多的企业和个人开始采用多账号矩阵的运营模式。这种模式能够有效扩大品牌影响力,覆盖更多细分用户群体,但同时也带来了账号管理复杂、内容发布效率低、数据分散难以整合、私域转化路径不清晰等一系列问题。

本文将从技术实现的角度,详细介绍一套完整的小红书矩阵系统的设计与开发方案,重点阐述如何通过技术手段实现私域流量的高效转化与精细化管理,为运营人员提供有力的技术支撑。

一、小红书矩阵系统的整体架构设计

小红书矩阵系统采用前后端分离的架构设计,前端使用Vue3+Element Plus构建用户界面,后端基于Django REST framework开发API接口,数据库采用MySQL存储结构化数据,Redis用于缓存热点数据和实现消息队列,Celery处理异步任务如定时发布、数据采集等。系统整体分为表现层、业务逻辑层、数据访问层和基础设施层四个层次,各层之间通过标准化接口进行通信,保证了系统的可维护性和可扩展性。

复制代码
# 项目结构设计
xiaohongshu_matrix/
├── backend/                 # 后端项目
│   ├── config/              # 配置文件
│   │   ├── settings.py      # 全局配置
│   │   ├── urls.py          # URL路由配置
│   │   └── celery.py        # Celery配置
│   ├── apps/                # 应用模块
│   │   ├── accounts/        # 账号管理模块
│   │   ├── content/         # 内容管理模块
│   │   ├── interaction/     # 互动管理模块
│   │   ├── conversion/      # 转化管理模块
│   │   ├── crm/             # 客户关系管理模块
│   │   └── security/        # 安全风控模块
│   ├── utils/               # 工具类
│   │   ├── xhs_api.py       # 小红书API封装
│   │   ├── data_processor.py# 数据处理工具
│   │   └── encryption.py    # 加密工具
│   ├── requirements.txt     # 依赖包列表
│   └── manage.py            # Django管理脚本
├── frontend/                # 前端项目
│   ├── src/
│   │   ├── components/      # 公共组件
│   │   ├── views/           # 页面视图
│   │   ├── api/             # API请求封装
│   │   └── store/           # 状态管理
│   └── package.json
└── docker-compose.yml       # Docker部署配置

# 全局配置示例
# config/settings.py
import os
from datetime import timedelta

BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))

SECRET_KEY = os.environ.get('SECRET_KEY', 'your-secret-key-here')
DEBUG = os.environ.get('DEBUG', 'False') == 'True'
ALLOWED_HOSTS = os.environ.get('ALLOWED_HOSTS', 'localhost,127.0.0.1').split(',')

# 数据库配置
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': os.environ.get('DB_NAME', 'xiaohongshu_matrix'),
        'USER': os.environ.get('DB_USER', 'root'),
        'PASSWORD': os.environ.get('DB_PASSWORD', 'password'),
        'HOST': os.environ.get('DB_HOST', 'localhost'),
        'PORT': os.environ.get('DB_PORT', '3306'),
        'OPTIONS': {
            'charset': 'utf8mb4',
            'init_command': "SET sql_mode='STRICT_TRANS_TABLES'"
        }
    }
}

# Redis配置
REDIS_URL = os.environ.get('REDIS_URL', 'redis://localhost:6379/0')
CACHES = {
    'default': {
        'BACKEND': 'django_redis.cache.RedisCache',
        'LOCATION': REDIS_URL,
        'OPTIONS': {
            'CLIENT_CLASS': 'django_redis.client.DefaultClient',
        }
    }
}

# Celery配置
CELERY_BROKER_URL = REDIS_URL
CELERY_RESULT_BACKEND = REDIS_URL
CELERY_ACCEPT_CONTENT = ['application/json']
CELERY_TASK_SERIALIZER = 'json'
CELERY_RESULT_SERIALIZER = 'json'
CELERY_TIMEZONE = 'Asia/Shanghai'
CELERY_BEAT_SCHEDULE = {
    'update-account-status-every-30-minutes': {
        'task': 'apps.accounts.tasks.update_account_status',
        'schedule': timedelta(minutes=30),
    },
    'collect-interaction-data-every-hour': {
        'task': 'apps.interaction.tasks.collect_interaction_data',
        'schedule': timedelta(hours=1),
    },
}

# 小红书API配置
XHS_API_BASE_URL = 'https://api.xiaohongshu.com'
XHS_API_TIMEOUT = 30
XHS_MAX_REQUESTS_PER_MINUTE = 60  # 限流控制

二、账号统一管理与状态监控模块

账号统一管理是小红书矩阵系统的基础功能,该模块负责管理所有小红书账号的基本信息、登录状态、权限分配等。系统支持批量导入账号信息,自动完成登录验证,并实时监控账号的在线状态、粉丝数量、获赞数、笔记数量等关键指标。当账号出现异常状态如登录失效、被限流、被封号等情况时,系统会及时发出告警通知,帮助运营人员快速处理问题。

复制代码
# 账号模型定义
# apps/accounts/models.py
from django.db import models
from django.utils import timezone

class Account(models.Model):
    STATUS_CHOICES = (
        ('active', '正常'),
        ('inactive', '未激活'),
        ('suspended', '被限流'),
        ('banned', '被封号'),
        ('login_expired', '登录失效'),
    )
    
    username = models.CharField(max_length=100, unique=True, verbose_name='账号用户名')
    password = models.CharField(max_length=255, verbose_name='账号密码')
    phone_number = models.CharField(max_length=20, blank=True, null=True, verbose_name='手机号')
    nickname = models.CharField(max_length=100, blank=True, null=True, verbose_name='昵称')
    avatar_url = models.URLField(blank=True, null=True, verbose_name='头像URL')
    description = models.TextField(blank=True, null=True, verbose_name='个人简介')
    followers_count = models.IntegerField(default=0, verbose_name='粉丝数')
    following_count = models.IntegerField(default=0, verbose_name='关注数')
    likes_count = models.IntegerField(default=0, verbose_name='获赞数')
    notes_count = models.IntegerField(default=0, verbose_name='笔记数')
    status = models.CharField(max_length=20, choices=STATUS_CHOICES, default='inactive', verbose_name='账号状态')
    last_login_time = models.DateTimeField(blank=True, null=True, verbose_name='最后登录时间')
    last_active_time = models.DateTimeField(blank=True, null=True, verbose_name='最后活跃时间')
    created_at = models.DateTimeField(auto_now_add=True, verbose_name='创建时间')
    updated_at = models.DateTimeField(auto_now=True, verbose_name='更新时间')
    cookie = models.TextField(blank=True, null=True, verbose_name='登录Cookie')
    proxy = models.CharField(max_length=255, blank=True, null=True, verbose_name='代理服务器')
    tags = models.CharField(max_length=255, blank=True, null=True, verbose_name='账号标签')
    operator = models.CharField(max_length=100, blank=True, null=True, verbose_name='运营人员')
    
    class Meta:
        verbose_name = '小红书账号'
        verbose_name_plural = '小红书账号'
        ordering = ['-created_at']
    
    def __str__(self):
        return self.nickname or self.username
    
    def update_status(self, new_status):
        self.status = new_status
        self.updated_at = timezone.now()
        self.save()
        
        # 记录状态变更日志
        AccountStatusLog.objects.create(
            account=self,
            old_status=self.status,
            new_status=new_status,
            remark=f"账号状态变更为{new_status}"
        )

class AccountStatusLog(models.Model):
    account = models.ForeignKey(Account, on_delete=models.CASCADE, related_name='status_logs', verbose_name='账号')
    old_status = models.CharField(max_length=20, choices=Account.STATUS_CHOICES, verbose_name='旧状态')
    new_status = models.CharField(max_length=20, choices=Account.STATUS_CHOICES, verbose_name='新状态')
    remark = models.TextField(blank=True, null=True, verbose_name='备注')
    created_at = models.DateTimeField(auto_now_add=True, verbose_name='创建时间')
    
    class Meta:
        verbose_name = '账号状态日志'
        verbose_name_plural = '账号状态日志'
        ordering = ['-created_at']

# 账号登录服务
# apps/accounts/services.py
import requests
from django.conf import settings
from utils.encryption import encrypt_cookie, decrypt_cookie
from .models import Account, AccountStatusLog

class AccountLoginService:
    def __init__(self):
        self.session = requests.Session()
        self.session.timeout = settings.XHS_API_TIMEOUT
        self.base_url = settings.XHS_API_BASE_URL
    
    def login(self, account_id):
        try:
            account = Account.objects.get(id=account_id)
            
            # 如果有保存的Cookie,先尝试使用Cookie登录
            if account.cookie:
                cookie = decrypt_cookie(account.cookie)
                self.session.cookies.update(cookie)
                if self._check_login_status():
                    account.update_status('active')
                    account.last_login_time = timezone.now()
                    account.last_active_time = timezone.now()
                    account.save()
                    return True, "Cookie登录成功"
            
            # Cookie登录失败,使用账号密码登录
            login_url = f"{self.base_url}/api/sns/v1/user/login"
            data = {
                'username': account.username,
                'password': account.password,
                'phone_number': account.phone_number
            }
            
            # 设置代理
            if account.proxy:
                self.session.proxies = {
                    'http': account.proxy,
                    'https': account.proxy
                }
            
            response = self.session.post(login_url, json=data)
            response.raise_for_status()
            result = response.json()
            
            if result.get('code') == 0:
                # 登录成功,保存Cookie
                cookie_dict = requests.utils.dict_from_cookiejar(self.session.cookies)
                encrypted_cookie = encrypt_cookie(cookie_dict)
                account.cookie = encrypted_cookie
                account.update_status('active')
                account.last_login_time = timezone.now()
                account.last_active_time = timezone.now()
                
                # 更新账号基本信息
                user_info = result.get('data', {}).get('user_info', {})
                account.nickname = user_info.get('nickname')
                account.avatar_url = user_info.get('avatar_url')
                account.description = user_info.get('description')
                account.followers_count = user_info.get('followers_count', 0)
                account.following_count = user_info.get('following_count', 0)
                account.likes_count = user_info.get('likes_count', 0)
                account.notes_count = user_info.get('notes_count', 0)
                account.save()
                
                return True, "账号密码登录成功"
            else:
                error_msg = result.get('msg', '登录失败')
                account.update_status('login_expired')
                return False, f"登录失败: {error_msg}"
                
        except Account.DoesNotExist:
            return False, "账号不存在"
        except Exception as e:
            return False, f"登录异常: {str(e)}"
    
    def _check_login_status(self):
        try:
            check_url = f"{self.base_url}/api/sns/v1/user/info"
            response = self.session.get(check_url)
            response.raise_for_status()
            result = response.json()
            return result.get('code') == 0
        except:
            return False

# 账号状态监控任务
# apps/accounts/tasks.py
from celery import shared_task
from django.utils import timezone
from .services import AccountLoginService
from .models import Account

@shared_task
def update_account_status():
    """定时更新所有账号状态"""
    accounts = Account.objects.exclude(status='banned')
    login_service = AccountLoginService()
    
    for account in accounts:
        try:
            # 检查登录状态
            if account.cookie:
                is_logged_in = login_service.login(account.id)
                if not is_logged_in:
                    account.update_status('login_expired')
            
            # 更新账号统计信息
            if account.status == 'active':
                # 调用API获取最新统计数据
                stats_url = f"{login_service.base_url}/api/sns/v1/user/stats"
                response = login_service.session.get(stats_url)
                response.raise_for_status()
                result = response.json()
                
                if result.get('code') == 0:
                    stats = result.get('data', {})
                    account.followers_count = stats.get('followers_count', 0)
                    account.following_count = stats.get('following_count', 0)
                    account.likes_count = stats.get('likes_count', 0)
                    account.notes_count = stats.get('notes_count', 0)
                    account.last_active_time = timezone.now()
                    account.save()
                    
        except Exception as e:
            print(f"更新账号{account.username}状态失败: {str(e)}")
            continue

三、内容批量发布与定时调度实现

内容批量发布是提高运营效率的关键功能,该模块支持批量上传图文和视频内容,设置发布时间、发布账号、话题标签等信息。系统采用Celery实现定时任务调度,能够按照预设的时间自动将内容发布到指定的小红书账号上。同时,系统还提供内容预览功能,让运营人员在发布前能够查看内容的最终效果,避免出现错误。

复制代码
# 内容模型定义
# apps/content/models.py
from django.db import models
from django.utils import timezone
from apps.accounts.models import Account

class Content(models.Model):
    TYPE_CHOICES = (
        ('image', '图文'),
        ('video', '视频'),
    )
    
    STATUS_CHOICES = (
        ('draft', '草稿'),
        ('pending', '待发布'),
        ('published', '已发布'),
        ('failed', '发布失败'),
        ('cancelled', '已取消'),
    )
    
    title = models.CharField(max_length=200, verbose_name='内容标题')
    content = models.TextField(verbose_name='内容正文')
    type = models.CharField(max_length=10, choices=TYPE_CHOICES, default='image', verbose_name='内容类型')
    cover_url = models.URLField(blank=True, null=True, verbose_name='封面URL')
    media_urls = models.TextField(verbose_name='媒体文件URL列表(逗号分隔)')
    tags = models.CharField(max_length=255, blank=True, null=True, verbose_name='话题标签(逗号分隔)')
    location = models.CharField(max_length=100, blank=True, null=True, verbose_name='地理位置')
    status = models.CharField(max_length=20, choices=STATUS_CHOICES, default='draft', verbose_name='内容状态')
    created_at = models.DateTimeField(auto_now_add=True, verbose_name='创建时间')
    updated_at = models.DateTimeField(auto_now=True, verbose_name='更新时间')
    publish_time = models.DateTimeField(blank=True, null=True, verbose_name='发布时间')
    creator = models.CharField(max_length=100, blank=True, null=True, verbose_name='创建者')
    
    class Meta:
        verbose_name = '内容'
        verbose_name_plural = '内容'
        ordering = ['-created_at']
    
    def __str__(self):
        return self.title

class PublishTask(models.Model):
    content = models.ForeignKey(Content, on_delete=models.CASCADE, related_name='publish_tasks', verbose_name='内容')
    account = models.ForeignKey(Account, on_delete=models.CASCADE, related_name='publish_tasks', verbose_name='发布账号')
    scheduled_time = models.DateTimeField(verbose_name='计划发布时间')
    actual_time = models.DateTimeField(blank=True, null=True, verbose_name='实际发布时间')
    status = models.CharField(max_length=20, choices=Content.STATUS_CHOICES, default='pending', verbose_name='任务状态')
    note_id = models.CharField(max_length=100, blank=True, null=True, verbose_name='小红书笔记ID')
    error_msg = models.TextField(blank=True, null=True, verbose_name='错误信息')
    celery_task_id = models.CharField(max_length=100, blank=True, null=True, verbose_name='Celery任务ID')
    created_at = models.DateTimeField(auto_now_add=True, verbose_name='创建时间')
    updated_at = models.DateTimeField(auto_now=True, verbose_name='更新时间')
    
    class Meta:
        verbose_name = '发布任务'
        verbose_name_plural = '发布任务'
        ordering = ['scheduled_time']
    
    def __str__(self):
        return f"{self.content.title} - {self.account.nickname}"

# 内容发布服务
# apps/content/services.py
import requests
import json
from django.conf import settings
from django.utils import timezone
from celery.result import AsyncResult
from apps.accounts.models import Account
from .models import Content, PublishTask
from .tasks import publish_content_task

class ContentPublishService:
    def __init__(self):
        self.base_url = settings.XHS_API_BASE_URL
    
    def create_publish_task(self, content_id, account_ids, scheduled_time):
        """创建批量发布任务"""
        try:
            content = Content.objects.get(id=content_id)
            
            # 检查内容状态
            if content.status not in ['draft', 'failed']:
                return False, "内容状态不允许发布"
            
            # 检查账号状态
            valid_accounts = []
            for account_id in account_ids:
                try:
                    account = Account.objects.get(id=account_id, status='active')
                    valid_accounts.append(account)
                except Account.DoesNotExist:
                    continue
            
            if not valid_accounts:
                return False, "没有可用的发布账号"
            
            # 更新内容状态
            content.status = 'pending'
            content.publish_time = scheduled_time
            content.save()
            
            # 创建发布任务
            task_ids = []
            for account in valid_accounts:
                publish_task = PublishTask.objects.create(
                    content=content,
                    account=account,
                    scheduled_time=scheduled_time,
                    status='pending'
                )
                
                # 调用Celery任务
                task = publish_content_task.apply_async(
                    args=[publish_task.id],
                    eta=scheduled_time
                )
                
                publish_task.celery_task_id = task.id
                publish_task.save()
                task_ids.append(task.id)
            
            return True, f"成功创建{len(valid_accounts)}个发布任务"
            
        except Content.DoesNotExist:
            return False, "内容不存在"
        except Exception as e:
            return False, f"创建发布任务失败: {str(e)}"
    
    def cancel_publish_task(self, task_id):
        """取消发布任务"""
        try:
            publish_task = PublishTask.objects.get(id=task_id)
            
            if publish_task.status != 'pending':
                return False, "只有待发布的任务可以取消"
            
            # 撤销Celery任务
            if publish_task.celery_task_id:
                result = AsyncResult(publish_task.celery_task_id)
                result.revoke(terminate=True)
            
            publish_task.status = 'cancelled'
            publish_task.save()
            
            # 检查是否还有其他待发布任务
            remaining_tasks = PublishTask.objects.filter(
                content=publish_task.content,
                status='pending'
            ).count()
            
            if remaining_tasks == 0:
                publish_task.content.status = 'draft'
                publish_task.content.save()
            
            return True, "发布任务已取消"
            
        except PublishTask.DoesNotExist:
            return False, "发布任务不存在"
        except Exception as e:
            return False, f"取消发布任务失败: {str(e)}"

# 内容发布任务
# apps/content/tasks.py
from celery import shared_task
from django.utils import timezone
import requests
from django.conf import settings
from utils.encryption import decrypt_cookie
from .models import PublishTask

@shared_task(bind=True, max_retries=3)
def publish_content_task(self, task_id):
    """发布内容到小红书"""
    try:
        publish_task = PublishTask.objects.get(id=task_id)
        
        # 检查任务状态
        if publish_task.status != 'pending':
            return
        
        account = publish_task.account
        content = publish_task.content
        
        # 准备发布数据
        publish_url = f"{settings.XHS_API_BASE_URL}/api/sns/v1/note/create"
        headers = {
            'Content-Type': 'application/json',
            'User-Agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 15_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.0 Mobile/15E148 Safari/604.1'
        }
        
        # 解密Cookie
        cookie = decrypt_cookie(account.cookie)
        cookie_str = '; '.join([f"{k}={v}" for k, v in cookie.items()])
        headers['Cookie'] = cookie_str
        
        # 构建请求数据
        data = {
            'title': content.title,
            'content': content.content,
            'type': content.type,
            'cover_url': content.cover_url,
            'media_urls': content.media_urls.split(','),
            'tags': content.tags.split(',') if content.tags else [],
            'location': content.location
        }
        
        # 设置代理
        proxies = {}
        if account.proxy:
            proxies = {
                'http': account.proxy,
                'https': account.proxy
            }
        
        # 发送发布请求
        response = requests.post(
            publish_url,
            headers=headers,
            json=data,
            proxies=proxies,
            timeout=settings.XHS_API_TIMEOUT
        )
        response.raise_for_status()
        result = response.json()
        
        if result.get('code') == 0:
            # 发布成功
            publish_task.status = 'published'
            publish_task.actual_time = timezone.now()
            publish_task.note_id = result.get('data', {}).get('note_id')
            publish_task.save()
            
            # 更新内容状态
            content.status = 'published'
            content.save()
            
            return f"内容发布成功,笔记ID: {publish_task.note_id}"
        else:
            error_msg = result.get('msg', '发布失败')
            publish_task.status = 'failed'
            publish_task.error_msg = error_msg
            publish_task.save()
            
            # 更新内容状态
            content.status = 'failed'
            content.save()
            
            raise Exception(f"发布失败: {error_msg}")
            
    except PublishTask.DoesNotExist:
        return "发布任务不存在"
    except Exception as e:
        # 重试任务
        self.retry(exc=e, countdown=60 * (self.request.retries + 1))

四、用户互动数据采集与分析系统

用户互动数据采集与分析系统负责收集小红书笔记的点赞、评论、收藏、分享等互动数据,并对这些数据进行统计分析,为运营决策提供数据支持。系统采用定时任务的方式,定期从小红书平台采集最新的互动数据,并将数据存储到数据库中。通过对数据的多维度分析,运营人员可以了解用户的兴趣偏好、内容的传播效果以及账号的运营状况。

复制代码
# 互动数据模型定义
# apps/interaction/models.py
from django.db import models
from apps.accounts.models import Account
from apps.content.models import PublishTask

class NoteInteraction(models.Model):
    publish_task = models.OneToOneField(PublishTask, on_delete=models.CASCADE, related_name='interaction', verbose_name='发布任务')
    note_id = models.CharField(max_length=100, unique=True, verbose_name='小红书笔记ID')
    likes_count = models.IntegerField(default=0, verbose_name='点赞数')
    comments_count = models.IntegerField(default=0, verbose_name='评论数')
    collects_count = models.IntegerField(default=0, verbose_name='收藏数')
    shares_count = models.IntegerField(default=0, verbose_name='分享数')
    views_count = models.IntegerField(default=0, verbose_name='浏览数')
    last_updated = models.DateTimeField(auto_now=True, verbose_name='最后更新时间')
    created_at = models.DateTimeField(auto_now_add=True, verbose_name='创建时间')
    
    class Meta:
        verbose_name = '笔记互动数据'
        verbose_name_plural = '笔记互动数据'
        ordering = ['-last_updated']
    
    def __str__(self):
        return f"{self.publish_task.content.title} - 互动数据"

class Comment(models.Model):
    note_interaction = models.ForeignKey(NoteInteraction, on_delete=models.CASCADE, related_name='comments', verbose_name='笔记互动数据')
    comment_id = models.CharField(max_length=100, unique=True, verbose_name='评论ID')
    user_nickname = models.CharField(max_length=100, verbose_name='评论用户昵称')
    user_avatar = models.URLField(blank=True, null=True, verbose_name='评论用户头像')
    content = models.TextField(verbose_name='评论内容')
    like_count = models.IntegerField(default=0, verbose_name='评论点赞数')
    reply_count = models.IntegerField(default=0, verbose_name='回复数')
    created_time = models.DateTimeField(verbose_name='评论时间')
    is_replied = models.BooleanField(default=False, verbose_name='是否已回复')
    reply_content = models.TextField(blank=True, null=True, verbose_name='回复内容')
    reply_time = models.DateTimeField(blank=True, null=True, verbose_name='回复时间')
    
    class Meta:
        verbose_name = '评论'
        verbose_name_plural = '评论'
        ordering = ['-created_time']
    
    def __str__(self):
        return f"{self.user_nickname}: {self.content[:50]}"

# 数据采集服务
# apps/interaction/services.py
import requests
from django.conf import settings
from django.utils import timezone
from utils.encryption import decrypt_cookie
from .models import NoteInteraction, Comment
from apps.content.models import PublishTask

class InteractionDataService:
    def __init__(self):
        self.base_url = settings.XHS_API_BASE_URL
    
    def collect_note_interaction(self, publish_task_id):
        """采集单篇笔记的互动数据"""
        try:
            publish_task = PublishTask.objects.get(id=publish_task_id, status='published')
            
            # 获取或创建互动数据记录
            note_interaction, created = NoteInteraction.objects.get_or_create(
                publish_task=publish_task,
                defaults={'note_id': publish_task.note_id}
            )
            
            account = publish_task.account
            
            # 准备请求
            interaction_url = f"{self.base_url}/api/sns/v1/note/{publish_task.note_id}/interaction"
            headers = {
                'User-Agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 15_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.0 Mobile/15E148 Safari/604.1'
            }
            
            # 解密Cookie
            cookie = decrypt_cookie(account.cookie)
            cookie_str = '; '.join([f"{k}={v}" for k, v in cookie.items()])
            headers['Cookie'] = cookie_str
            
            # 设置代理
            proxies = {}
            if account.proxy:
                proxies = {
                    'http': account.proxy,
                    'https': account.proxy
                }
            
            # 发送请求
            response = requests.get(
                interaction_url,
                headers=headers,
                proxies=proxies,
                timeout=settings.XHS_API_TIMEOUT
            )
            response.raise_for_status()
            result = response.json()
            
            if result.get('code') == 0:
                data = result.get('data', {})
                
                # 更新互动数据
                note_interaction.likes_count = data.get('likes_count', 0)
                note_interaction.comments_count = data.get('comments_count', 0)
                note_interaction.collects_count = data.get('collects_count', 0)
                note_interaction.shares_count = data.get('shares_count', 0)
                note_interaction.views_count = data.get('views_count', 0)
                note_interaction.save()
                
                # 采集评论数据
                self._collect_comments(note_interaction, headers, proxies)
                
                return True, "互动数据采集成功"
            else:
                error_msg = result.get('msg', '数据采集失败')
                return False, f"数据采集失败: {error_msg}"
                
        except PublishTask.DoesNotExist:
            return False, "发布任务不存在或未发布"
        except Exception as e:
            return False, f"数据采集异常: {str(e)}"
    
    def _collect_comments(self, note_interaction, headers, proxies):
        """采集笔记评论"""
        try:
            comments_url = f"{self.base_url}/api/sns/v1/note/{note_interaction.note_id}/comments"
            page = 1
            page_size = 20
            
            while True:
                params = {
                    'page': page,
                    'page_size': page_size
                }
                
                response = requests.get(
                    comments_url,
                    headers=headers,
                    params=params,
                    proxies=proxies,
                    timeout=settings.XHS_API_TIMEOUT
                )
                response.raise_for_status()
                result = response.json()
                
                if result.get('code') != 0:
                    break
                
                comments = result.get('data', {}).get('comments', [])
                if not comments:
                    break
                
                for comment_data in comments:
                    Comment.objects.get_or_create(
                        comment_id=comment_data.get('comment_id'),
                        defaults={
                            'note_interaction': note_interaction,
                            'user_nickname': comment_data.get('user_nickname'),
                            'user_avatar': comment_data.get('user_avatar'),
                            'content': comment_data.get('content'),
                            'like_count': comment_data.get('like_count', 0),
                            'reply_count': comment_data.get('reply_count', 0),
                            'created_time': timezone.datetime.fromtimestamp(comment_data.get('created_time', 0))
                        }
                    )
                
                page += 1
                
        except Exception as e:
            print(f"采集评论失败: {str(e)}")

# 数据采集任务
# apps/interaction/tasks.py
from celery import shared_task
from .services import InteractionDataService
from apps.content.models import PublishTask

@shared_task
def collect_interaction_data():
    """定时采集所有已发布笔记的互动数据"""
    publish_tasks = PublishTask.objects.filter(status='published')
    data_service = InteractionDataService()
    
    for publish_task in publish_tasks:
        try:
            data_service.collect_note_interaction(publish_task.id)
        except Exception as e:
            print(f"采集任务{publish_task.id}失败: {str(e)}")
            continue

五、私域流量转化路径追踪技术

私域流量转化路径追踪是实现精准营销的核心技术,该模块能够追踪用户从小红书笔记点击到最终转化的完整路径。系统通过在笔记内容中插入唯一的追踪参数,识别不同来源的用户流量,并记录用户的行为轨迹。通过分析转化路径数据,运营人员可以了解哪些内容和渠道的转化效果最好,从而优化运营策略,提高私域流量的转化效率。

复制代码
# 转化追踪模型定义
# apps/conversion/models.py
from django.db import models
from apps.accounts.models import Account
from apps.content.models import PublishTask

class ConversionLink(models.Model):
    publish_task = models.ForeignKey(PublishTask, on_delete=models.CASCADE, related_name='conversion_links', verbose_name='发布任务')
    original_url = models.URLField(verbose_name='原始链接')
    tracking_code = models.CharField(max_length=50, unique=True, verbose_name='追踪码')
    short_url = models.URLField(verbose_name='短链接')
    click_count = models.IntegerField(default=0, verbose_name='点击次数')
    unique_visitor_count = models.IntegerField(default=0, verbose_name='独立访客数')
    conversion_count = models.IntegerField(default=0, verbose_name='转化次数')
    created_at = models.DateTimeField(auto_now_add=True, verbose_name='创建时间')
    updated_at = models.DateTimeField(auto_now=True, verbose_name='更新时间')
    
    class Meta:
        verbose_name = '转化链接'
        verbose_name_plural = '转化链接'
        ordering = ['-created_at']
    
    def __str__(self):
        return f"{self.tracking_code} - {self.original_url}"

class UserBehavior(models.Model):
    conversion_link = models.ForeignKey(ConversionLink, on_delete=models.CASCADE, related_name='user_behaviors', verbose_name='转化链接')
    visitor_id = models.CharField(max_length=100, verbose_name='访客ID')
    ip_address = models.CharField(max_length=50, verbose_name='IP地址')
    user_agent = models.TextField(verbose_name='用户代理')
    referer = models.URLField(blank=True, null=True, verbose_name='来源页面')
    click_time = models.DateTimeField(auto_now_add=True, verbose_name='点击时间')
    is_converted = models.BooleanField(default=False, verbose_name='是否转化')
    conversion_time = models.DateTimeField(blank=True, null=True, verbose_name='转化时间')
    conversion_type = models.CharField(max_length=50, blank=True, null=True, verbose_name='转化类型')
    
    class Meta:
        verbose_name = '用户行为'
        verbose_name_plural = '用户行为'
        ordering = ['-click_time']
    
    def __str__(self):
        return f"{self.visitor_id} - {self.click_time}"

# 转化链接服务
# apps/conversion/services.py
import hashlib
import time
import base64
from django.conf import settings
from django.utils import timezone
from .models import ConversionLink, UserBehavior
from apps.content.models import PublishTask

class ConversionLinkService:
    def __init__(self):
        self.base_short_url = settings.BASE_SHORT_URL or 'http://localhost:8000/r/'
    
    def generate_tracking_code(self, publish_task_id, original_url):
        """生成唯一追踪码"""
        timestamp = str(int(time.time()))
        data = f"{publish_task_id}-{original_url}-{timestamp}"
        hash_obj = hashlib.md5(data.encode('utf-8'))
        hash_hex = hash_obj.hexdigest()
        # 取前8位作为追踪码
        return hash_hex[:8]
    
    def create_conversion_link(self, publish_task_id, original_url):
        """创建转化链接"""
        try:
            publish_task = PublishTask.objects.get(id=publish_task_id)
            
            # 生成追踪码
            tracking_code = self.generate_tracking_code(publish_task_id, original_url)
            
            # 生成短链接
            short_url = f"{self.base_short_url}{tracking_code}"
            
            # 创建转化链接记录
            conversion_link = ConversionLink.objects.create(
                publish_task=publish_task,
                original_url=original_url,
                tracking_code=tracking_code,
                short_url=short_url
            )
            
            return True, conversion_link
            
        except PublishTask.DoesNotExist:
            return False, "发布任务不存在"
        except Exception as e:
            return False, f"创建转化链接失败: {str(e)}"
    
    def track_click(self, tracking_code, visitor_id, ip_address, user_agent, referer=None):
        """追踪用户点击"""
        try:
            conversion_link = ConversionLink.objects.get(tracking_code=tracking_code)
            
            # 记录用户行为
            user_behavior = UserBehavior.objects.create(
                conversion_link=conversion_link,
                visitor_id=visitor_id,
                ip_address=ip_address,
                user_agent=user_agent,
                referer=referer
            )
            
            # 更新点击统计
            conversion_link.click_count += 1
            
            # 检查是否是新访客
            existing_visitor = UserBehavior.objects.filter(
                conversion_link=conversion_link,
                visitor_id=visitor_id
            ).exists()
            
            if not existing_visitor:
                conversion_link.unique_visitor_count += 1
            
            conversion_link.save()
            
            return True, conversion_link.original_url
            
        except ConversionLink.DoesNotExist:
            return False, "追踪码不存在"
        except Exception as e:
            return False, f"追踪点击失败: {str(e)}"
    
    def track_conversion(self, visitor_id, conversion_type):
        """追踪用户转化"""
        try:
            # 查找该访客最近的点击记录
            user_behavior = UserBehavior.objects.filter(
                visitor_id=visitor_id,
                is_converted=False
            ).order_by('-click_time').first()
            
            if not user_behavior:
                return False, "未找到该访客的点击记录"
            
            # 更新转化状态
            user_behavior.is_converted = True
            user_behavior.conversion_time = timezone.now()
            user_behavior.conversion_type = conversion_type
            user_behavior.save()
            
            # 更新转化统计
            conversion_link = user_behavior.conversion_link
            conversion_link.conversion_count += 1
            conversion_link.save()
            
            return True, "转化追踪成功"
            
        except Exception as e:
            return False, f"追踪转化失败: {str(e)}"

# 转化追踪视图
# apps/conversion/views.py
from django.http import HttpResponseRedirect, JsonResponse
from django.views import View
from .services import ConversionLinkService
import uuid

class RedirectView(View):
    def get(self, request, tracking_code):
        """短链接重定向"""
        visitor_id = request.COOKIES.get('visitor_id')
        if not visitor_id:
            visitor_id = str(uuid.uuid4())
        
        ip_address = request.META.get('REMOTE_ADDR')
        user_agent = request.META.get('HTTP_USER_AGENT', '')
        referer = request.META.get('HTTP_REFERER')
        
        service = ConversionLinkService()
        success, result = service.track_click(
            tracking_code=tracking_code,
            visitor_id=visitor_id,
            ip_address=ip_address,
            user_agent=user_agent,
            referer=referer
        )
        
        if success:
            response = HttpResponseRedirect(result)
            # 设置访客ID Cookie,有效期30天
            response.set_cookie('visitor_id', visitor_id, max_age=30*24*60*60)
            return response
        else:
            return HttpResponseRedirect('/404')

class ConversionTrackView(View):
    def post(self, request):
        """转化追踪接口"""
        visitor_id = request.COOKIES.get('visitor_id')
        conversion_type = request.POST.get('conversion_type')
        
        if not visitor_id or not conversion_type:
            return JsonResponse({'success': False, 'message': '参数不完整'})
        
        service = ConversionLinkService()
        success, message = service.track_conversion(visitor_id, conversion_type)
        
        return JsonResponse({'success': success, 'message': message})

六、客户关系管理与标签体系构建

客户关系管理模块负责管理从小红书平台引流过来的私域用户信息,系统支持自动同步用户的基本信息、互动历史、转化记录等数据。标签体系是客户关系管理的核心,系统允许运营人员根据用户的行为特征、兴趣偏好、消费能力等维度为用户打上标签,实现用户的精细化分类管理。通过标签体系,运营人员可以针对不同类型的用户制定个性化的营销策略,提高用户的活跃度和转化率。

复制代码
# CRM模型定义
# apps/crm/models.py
from django.db import models
from django.utils import timezone

class Customer(models.Model):
    GENDER_CHOICES = (
        ('male', '男'),
        ('female', '女'),
        ('unknown', '未知'),
    )
    
    SOURCE_CHOICES = (
        ('xiaohongshu', '小红书'),
        ('wechat', '微信'),
        ('douyin', '抖音'),
        ('other', '其他'),
    )
    
    STATUS_CHOICES = (
        ('active', '活跃'),
        ('inactive', '不活跃'),
        ('lost', '流失'),
    )
    
    name = models.CharField(max_length=100, blank=True, null=True, verbose_name='姓名')
    phone = models.CharField(max_length=20, blank=True, null=True, verbose_name='手机号')
    wechat_id = models.CharField(max_length=100, blank=True, null=True, unique=True, verbose_name='微信号')
    email = models.EmailField(blank=True, null=True, verbose_name='邮箱')
    gender = models.CharField(max_length=10, choices=GENDER_CHOICES, default='unknown', verbose_name='性别')
    age = models.IntegerField(blank=True, null=True, verbose_name='年龄')
    city = models.CharField(max_length=50, blank=True, null=True, verbose_name='城市')
    source = models.CharField(max_length=20, choices=SOURCE_CHOICES, default='xiaohongshu', verbose_name='来源渠道')
    source_note_id = models.CharField(max_length=100, blank=True, null=True, verbose_name='来源笔记ID')
    first_contact_time = models.DateTimeField(default=timezone.now, verbose_name='首次接触时间')
    last_contact_time = models.DateTimeField(default=timezone.now, verbose_name='最后接触时间')
    status = models.CharField(max_length=20, choices=STATUS_CHOICES, default='active', verbose_name='客户状态')
    total_consumption = models.DecimalField(max_digits=10, decimal_places=2, default=0, verbose_name='总消费金额')
    order_count = models.IntegerField(default=0, verbose_name='订单数')
    remark = models.TextField(blank=True, null=True, verbose_name='备注')
    created_at = models.DateTimeField(auto_now_add=True, verbose_name='创建时间')
    updated_at = models.DateTimeField(auto_now=True, verbose_name='更新时间')
    
    class Meta:
        verbose_name = '客户'
        verbose_name_plural = '客户'
        ordering = ['-created_at']
    
    def __str__(self):
        return self.name or self.wechat_id or self.phone or str(self.id)

class Tag(models.Model):
    name = models.CharField(max_length=50, unique=True, verbose_name='标签名称')
    color = models.CharField(max_length=20, default='#1890ff', verbose_name='标签颜色')
    description = models.TextField(blank=True, null=True, verbose_name='标签描述')
    created_at = models.DateTimeField(auto_now_add=True, verbose_name='创建时间')
    
    class Meta:
        verbose_name = '标签'
        verbose_name_plural = '标签'
        ordering = ['name']
    
    def __str__(self):
        return self.name

class CustomerTag(models.Model):
    customer = models.ForeignKey(Customer, on_delete=models.CASCADE, related_name='customer_tags', verbose_name='客户')
    tag = models.ForeignKey(Tag, on_delete=models.CASCADE, related_name='customer_tags', verbose_name='标签')
    created_at = models.DateTimeField(auto_now_add=True, verbose_name='创建时间')
    
    class Meta:
        verbose_name = '客户标签'
        verbose_name_plural = '客户标签'
        unique_together = ('customer', 'tag')
    
    def __str__(self):
        return f"{self.customer} - {self.tag}"

class InteractionRecord(models.Model):
    TYPE_CHOICES = (
        ('message', '消息'),
        ('call', '电话'),
        ('meeting', '会面'),
        ('other', '其他'),
    )
    
    customer = models.ForeignKey(Customer, on_delete=models.CASCADE, related_name='interaction_records', verbose_name='客户')
    type = models.CharField(max_length=20, choices=TYPE_CHOICES, default='message', verbose_name='互动类型')
    content = models.TextField(verbose_name='互动内容')
    interaction_time = models.DateTimeField(default=timezone.now, verbose_name='互动时间')
    operator = models.CharField(max_length=100, verbose_name='操作人员')
    created_at = models.DateTimeField(auto_now_add=True, verbose_name='创建时间')
    
    class Meta:
        verbose_name = '互动记录'
        verbose_name_plural = '互动记录'
        ordering = ['-interaction_time']
    
    def __str__(self):
        return f"{self.customer} - {self.type} - {self.interaction_time}"

# CRM服务
# apps/crm/services.py
from django.utils import timezone
from .models import Customer, Tag, CustomerTag, InteractionRecord
from apps.conversion.models import UserBehavior

class CRMService:
    def create_customer_from_behavior(self, user_behavior_id, wechat_id, **kwargs):
        """从用户行为记录创建客户"""
        try:
            user_behavior = UserBehavior.objects.get(id=user_behavior_id)
            
            # 创建客户
            customer = Customer.objects.create(
                wechat_id=wechat_id,
                source='xiaohongshu',
                source_note_id=user_behavior.conversion_link.publish_task.note_id,
                first_contact_time=user_behavior.click_time,
                last_contact_time=timezone.now(),
                **kwargs
            )
            
            # 根据来源笔记自动打标签
            publish_task = user_behavior.conversion_link.publish_task
            content_tags = publish_task.content.tags.split(',') if publish_task.content.tags else []
            
            for tag_name in content_tags:
                tag_name = tag_name.strip()
                if tag_name:
                    tag, created = Tag.objects.get_or_create(name=tag_name)
                    CustomerTag.objects.get_or_create(customer=customer, tag=tag)
            
            return True, customer
            
        except UserBehavior.DoesNotExist:
            return False, "用户行为记录不存在"
        except Exception as e:
            return False, f"创建客户失败: {str(e)}"
    
    def add_tag_to_customer(self, customer_id, tag_id):
        """为客户添加标签"""
        try:
            customer = Customer.objects.get(id=customer_id)
            tag = Tag.objects.get(id=tag_id)
            
            customer_tag, created = CustomerTag.objects.get_or_create(
                customer=customer,
                tag=tag
            )
            
            if created:
                return True, "标签添加成功"
            else:
                return False, "客户已拥有该标签"
                
        except Customer.DoesNotExist:
            return False, "客户不存在"
        except Tag.DoesNotExist:
            return False, "标签不存在"
        except Exception as e:
            return False, f"添加标签失败: {str(e)}"
    
    def add_interaction_record(self, customer_id, type, content, operator):
        """添加互动记录"""
        try:
            customer = Customer.objects.get(id=customer_id)
            
            interaction_record = InteractionRecord.objects.create(
                customer=customer,
                type=type,
                content=content,
                operator=operator
            )
            
            # 更新客户最后接触时间
            customer.last_contact_time = timezone.now()
            customer.save()
            
            return True, interaction_record
            
        except Customer.DoesNotExist:
            return False, "客户不存在"
        except Exception as e:
            return False, f"添加互动记录失败: {str(e)}"
    
    def get_customers_by_tags(self, tag_ids):
        """根据标签筛选客户"""
        try:
            customers = Customer.objects.filter(
                customer_tags__tag_id__in=tag_ids
            ).distinct()
            return True, customers
        except Exception as e:
            return False, f"筛选客户失败: {str(e)}"

七、数据安全与账号风控机制

数据安全与账号风控是小红书矩阵系统不可忽视的重要部分,该模块负责保护系统中的敏感数据如账号密码、Cookie信息等,并对账号的操作行为进行实时监控,防止账号被封禁。系统采用AES加密算法对敏感数据进行加密存储,确保数据在传输和存储过程中的安全性。同时,系统还实现了IP代理池、请求频率限制、操作行为模拟等风控措施,降低账号被平台检测到的风险。

复制代码
# 安全工具类
# utils/encryption.py
import base64
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad, unpad
from django.conf import settings

# 加密密钥和IV
SECRET_KEY = settings.ENCRYPTION_SECRET_KEY.encode('utf-8')[:32]  # 256位密钥
IV = settings.ENCRYPTION_IV.encode('utf-8')[:16]  # 128位IV

def encrypt_cookie(cookie_dict):
    """加密Cookie字典"""
    try:
        # 将字典转换为JSON字符串
        import json
        cookie_str = json.dumps(cookie_dict)
        
        # 创建AES加密器
        cipher = AES.new(SECRET_KEY, AES.MODE_CBC, IV)
        
        # 加密数据
        padded_data = pad(cookie_str.encode('utf-8'), AES.block_size)
        encrypted_data = cipher.encrypt(padded_data)
        
        # Base64编码
        encrypted_base64 = base64.b64encode(encrypted_data).decode('utf-8')
        
        return encrypted_base64
    except Exception as e:
        raise Exception(f"加密Cookie失败: {str(e)}")

def decrypt_cookie(encrypted_base64):
    """解密Cookie"""
    try:
        # Base64解码
        encrypted_data = base64.b64decode(encrypted_base64)
        
        # 创建AES解密器
        cipher = AES.new(SECRET_KEY, AES.MODE_CBC, IV)
        
        # 解密数据
        decrypted_data = cipher.decrypt(encrypted_data)
        unpadded_data = unpad(decrypted_data, AES.block_size)
        
        # 转换为字典
        import json
        cookie_dict = json.loads(unpadded_data.decode('utf-8'))
        
        return cookie_dict
    except Exception as e:
        raise Exception(f"解密Cookie失败: {str(e)}")

# 代理池模型
# apps/security/models.py
from django.db import models

class ProxyServer(models.Model):
    TYPE_CHOICES = (
        ('http', 'HTTP'),
        ('https', 'HTTPS'),
        ('socks5', 'SOCKS5'),
    )
    
    STATUS_CHOICES = (
        ('active', '可用'),
        ('inactive', '不可用'),
        ('testing', '测试中'),
    )
    
    ip = models.CharField(max_length=50, verbose_name='IP地址')
    port = models.IntegerField(verbose_name='端口')
    type = models.CharField(max_length=10, choices=TYPE_CHOICES, default='http', verbose_name='代理类型')
    username = models.CharField(max_length=50, blank=True, null=True, verbose_name='用户名')
    password = models.CharField(max_length=50, blank=True, null=True, verbose_name='密码')
    status = models.CharField(max_length=20, choices=STATUS_CHOICES, default='testing', verbose_name='状态')
    response_time = models.IntegerField(blank=True, null=True, verbose_name='响应时间(ms)')
    last_test_time = models.DateTimeField(blank=True, null=True, verbose_name='最后测试时间')
    success_count = models.IntegerField(default=0, verbose_name='成功次数')
    fail_count = models.IntegerField(default=0, verbose_name='失败次数')
    created_at = models.DateTimeField(auto_now_add=True, verbose_name='创建时间')
    updated_at = models.DateTimeField(auto_now=True, verbose_name='更新时间')
    
    class Meta:
        verbose_name = '代理服务器'
        verbose_name_plural = '代理服务器'
        ordering = ['response_time']
    
    def __str__(self):
        return f"{self.type}://{self.ip}:{self.port}"
    
    def get_proxy_url(self):
        """获取代理URL"""
        if self.username and self.password:
            return f"{self.type}://{self.username}:{self.password}@{self.ip}:{self.port}"
        else:
            return f"{self.type}://{self.ip}:{self.port}"

# 代理池服务
# apps/security/services.py
import requests
import time
import random
from django.utils import timezone
from .models import ProxyServer

class ProxyPoolService:
    def __init__(self):
        self.test_url = 'https://www.baidu.com'
        self.timeout = 5
    
    def test_proxy(self, proxy_id):
        """测试代理是否可用"""
        try:
            proxy = ProxyServer.objects.get(id=proxy_id)
            proxy.status = 'testing'
            proxy.save()
            
            proxy_url = proxy.get_proxy_url()
            proxies = {
                'http': proxy_url,
                'https': proxy_url
            }
            
            start_time = time.time()
            response = requests.get(
                self.test_url,
                proxies=proxies,
                timeout=self.timeout
            )
            response.raise_for_status()
            
            end_time = time.time()
            response_time = int((end_time - start_time) * 1000)
            
            proxy.status = 'active'
            proxy.response_time = response_time
            proxy.last_test_time = timezone.now()
            proxy.success_count += 1
            proxy.save()
            
            return True, f"代理可用,响应时间: {response_time}ms"
            
        except ProxyServer.DoesNotExist:
            return False, "代理不存在"
        except Exception as e:
            proxy.status = 'inactive'
            proxy.last_test_time = timezone.now()
            proxy.fail_count += 1
            proxy.save()
            return False, f"代理不可用: {str(e)}"
    
    def get_random_proxy(self):
        """获取随机可用代理"""
        active_proxies = ProxyServer.objects.filter(status='active')
        if not active_proxies.exists():
            return None
        
        # 按响应时间加权随机选择
        total_weight = sum(1000 / (proxy.response_time + 1) for proxy in active_proxies)
        random_value = random.uniform(0, total_weight)
        
        current_weight = 0
        for proxy in active_proxies:
            current_weight += 1000 / (proxy.response_time + 1)
            if current_weight >= random_value:
                return proxy.get_proxy_url()
        
        return active_proxies.first().get
相关推荐
AI_yangxi2 小时前
短视频矩阵系统服务商
大数据·人工智能·矩阵
甄心爱学习2 小时前
【项目实训(个人11)】
python·个人开发
装不满的克莱因瓶3 小时前
实现矩阵的转置:从数学原理到 NumPy 实战
线性代数·机器学习·矩阵·数据分析·numpy·特征分解
吃好睡好便好5 小时前
矩阵旋转的计算
学习·线性代数·算法·矩阵
法雅特吉他6 小时前
入门吉他选购指南:桶型、材质、工艺对吉他性能的影响
经验分享·新媒体运营·学习方法·业界资讯·流量运营·材质·内容运营
列星随旋6 小时前
矩阵快速幂
java·算法·矩阵
2501_915106326 小时前
iOS开发工具有哪些?iOS 开发每个阶段的实用工具
ide·vscode·ios·objective-c·个人开发·swift·敏捷流程
装不满的克莱因瓶7 小时前
机器学习和数据科学的基石:NumPy详解与实战技巧
人工智能·线性代数·机器学习·ai·矩阵·numpy
爱分享软件的学长7 小时前
GitHub CLI 2.92.0 官方版下载(夸克网盘+百度网盘,SHA256校验)
windows·开源软件·软件下载