小红书矩阵软件多设备批量管理自动化脚本编写
小红书矩阵软件作为当下内容创作者和运营者提升效率的核心工具,其多设备批量管理能力直接决定了矩阵账号的运营效果。在没有自动化脚本辅助的情况下,手动管理数十台设备上的小红书账号不仅耗时耗力,还容易出现操作失误、发布时间不一致等问题。
本文将从技术角度出发,分享如何基于Python和ADB协议编写一套完整的多设备批量管理自动化脚本,实现设备连接、账号登录、内容发布、互动操作等全流程自动化。这套脚本经过实际项目验证,能够稳定管理50台以上的安卓设备,大幅降低人工成本,同时通过精细化的行为模拟有效规避平台风控检测。
一、小红书矩阵软件多设备管理的核心痛点与技术选型
在开发小红书矩阵软件配套的自动化脚本之前,我首先梳理了多设备管理过程中最常见的几个痛点。第一个痛点是设备连接的不稳定性,尤其是在使用USB集线器连接大量设备时,经常会出现设备离线、连接中断的情况,需要人工反复插拔。第二个痛点是任务执行的同步性问题,手动操作无法保证所有设备在同一时间执行相同的任务,导致内容发布的时间分散,影响流量效果。第三个痛点是风控规避难度大,机械重复的操作很容易被平台检测到,导致账号被限流甚至封禁。
基于这些痛点,我最终选择了Python作为主要开发语言,结合ADB(Android Debug Bridge)协议实现与安卓设备的通信。Python拥有丰富的第三方库,如subprocess用于执行系统命令、threading用于多线程任务调度、PIL用于图像处理等,能够快速开发出功能完善的脚本。ADB协议则是谷歌官方提供的安卓调试工具,无需root设备即可实现应用安装、界面操作、文件传输等功能,兼容性好且安全性高。相比其他自动化框架如Appium,纯ADB脚本的运行速度更快,资源占用更低,更适合大规模多设备并发场景。
import subprocess
import threading
import time
import os
import random
from PIL import Image
import logging
from datetime import datetime
import json
# 配置日志系统
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(levelname)s - %(message)s',
handlers=[
logging.FileHandler('matrix_automation.log', encoding='utf-8'),
logging.StreamHandler()
]
)
logger = logging.getLogger(__name__)
# 全局配置
CONFIG = {
"adb_path": "adb", # 如果adb不在系统PATH中,请填写完整路径
"devices": [],
"task_interval": (3, 8), # 任务执行间隔时间范围(秒)
"max_retry_times": 3,
"image_quality": 80,
"max_concurrent_tasks": 10 # 最大并发任务数
}
# 设备状态枚举
DEVICE_STATUS = {
"OFFLINE": "offline",
"ONLINE": "online",
"BUSY": "busy",
"ERROR": "error"
}
# 任务类型枚举
TASK_TYPE = {
"START_APP": "start_app",
"LOGIN": "login",
"POST_CONTENT": "post_content",
"LIKE": "like",
"COMMENT": "comment",
"FOLLOW": "follow"
}
class Device:
"""设备类,封装单个设备的信息和操作方法"""
def __init__(self, device_id):
self.device_id = device_id
self.status = DEVICE_STATUS["OFFLINE"]
self.current_task = None
self.last_heartbeat = time.time()
self.retry_count = 0
def execute_adb_command(self, command, timeout=30):
"""执行ADB命令"""
full_command = f'{CONFIG["adb_path"]} -s {self.device_id} {command}'
try:
result = subprocess.run(
full_command,
shell=True,
capture_output=True,
text=True,
timeout=timeout
)
if result.returncode == 0:
return result.stdout.strip()
else:
logger.error(f"设备{self.device_id}执行命令失败: {result.stderr}")
return None
except subprocess.TimeoutExpired:
logger.error(f"设备{self.device_id}执行命令超时")
self.status = DEVICE_STATUS["ERROR"]
return None
except Exception as e:
logger.error(f"设备{self.device_id}执行命令发生异常: {str(e)}")
self.status = DEVICE_STATUS["ERROR"]
return None
def check_connection(self):
"""检查设备连接状态"""
result = self.execute_adb_command("get-state")
if result == "device":
self.status = DEVICE_STATUS["ONLINE"]
self.last_heartbeat = time.time()
self.retry_count = 0
return True
else:
self.status = DEVICE_STATUS["OFFLINE"]
return False
def wake_up(self):
"""唤醒设备屏幕"""
self.execute_adb_command("shell input keyevent 26") # 电源键
time.sleep(1)
self.execute_adb_command("shell input swipe 500 1500 500 500") # 上滑解锁
time.sleep(1)
logger.info(f"设备{self.device_id}已唤醒")
二、ADB基础通信与设备批量连接实现
ADB通信是整个小红书矩阵软件自动化脚本的基础,所有的设备操作都依赖于ADB命令的执行。在开始编写具体功能之前,我们首先需要实现设备的自动发现、连接和状态监控功能。ADB提供了devices命令来列出当前连接的所有设备,但这个命令只能获取设备ID,无法提供更多的设备信息,也不能自动处理连接断开的情况。
为了解决这个问题,我设计了一个设备管理类,用于维护所有在线设备的列表和状态。脚本启动时会自动扫描所有连接的设备,并为每个设备创建一个Device对象。同时,启动一个独立的心跳线程,每隔一段时间检查一次所有设备的连接状态,如果发现设备离线,会尝试自动重连。如果重连次数超过设定的最大值,则将该设备标记为错误状态,并记录到日志中。
class DeviceManager:
"""设备管理器,负责所有设备的管理和调度"""
def __init__(self):
self.devices = {}
self._stop_event = threading.Event()
self._heartbeat_thread = None
def scan_devices(self):
"""扫描所有连接的设备"""
logger.info("开始扫描设备...")
try:
result = subprocess.run(
f'{CONFIG["adb_path"]} devices',
shell=True,
capture_output=True,
text=True,
timeout=10
)
if result.returncode != 0:
logger.error(f"扫描设备失败: {result.stderr}")
return
lines = result.stdout.strip().split('\n')[1:] # 跳过第一行标题
current_device_ids = set()
for line in lines:
if '\tdevice' in line:
device_id = line.split('\t')[0]
current_device_ids.add(device_id)
if device_id not in self.devices:
device = Device(device_id)
if device.check_connection():
self.devices[device_id] = device
logger.info(f"发现新设备: {device_id}")
else:
logger.warning(f"设备{device_id}连接失败")
# 移除不再连接的设备
for device_id in list(self.devices.keys()):
if device_id not in current_device_ids:
logger.warning(f"设备{device_id}已断开连接")
del self.devices[device_id]
logger.info(f"设备扫描完成,当前在线设备数: {len(self.devices)}")
CONFIG["devices"] = list(self.devices.keys())
except Exception as e:
logger.error(f"扫描设备发生异常: {str(e)}")
def start_heartbeat(self):
"""启动心跳线程,定期检查设备状态"""
def heartbeat_loop():
while not self._stop_event.is_set():
try:
for device in self.devices.values():
if not device.check_connection():
logger.warning(f"设备{device.device_id}离线,尝试重连...")
device.retry_count += 1
if device.retry_count >= CONFIG["max_retry_times"]:
logger.error(f"设备{device.device_id}重连次数超过上限,标记为错误状态")
device.status = DEVICE_STATUS["ERROR"]
# 扫描新设备
self.scan_devices()
# 等待下一次心跳
for _ in range(30):
if self._stop_event.is_set():
break
time.sleep(1)
except Exception as e:
logger.error(f"心跳线程发生异常: {str(e)}")
time.sleep(5)
self._heartbeat_thread = threading.Thread(target=heartbeat_loop, daemon=True)
self._heartbeat_thread.start()
logger.info("设备心跳线程已启动")
def stop(self):
"""停止设备管理器"""
logger.info("正在停止设备管理器...")
self._stop_event.set()
if self._heartbeat_thread and self._heartbeat_thread.is_alive():
self._heartbeat_thread.join()
logger.info("设备管理器已停止")
def get_available_devices(self):
"""获取所有可用的设备"""
return [device for device in self.devices.values() if device.status == DEVICE_STATUS["ONLINE"]]
def get_device_by_id(self, device_id):
"""根据设备ID获取设备对象"""
return self.devices.get(device_id)
# 初始化设备管理器
device_manager = DeviceManager()
三、设备状态监控与异常自动重连机制
在小红书矩阵软件的实际运行过程中,设备连接不稳定是最常见的问题之一。导致设备离线的原因有很多,比如USB接触不良、设备电量耗尽、系统卡顿等。如果没有完善的异常处理机制,一旦某个设备离线,就会导致分配给它的任务执行失败,影响整个矩阵的运营效果。
为了解决这个问题,我在设备管理类中加入了详细的状态监控和异常自动重连机制。每个设备对象都有一个状态属性,用于标识当前设备是在线、离线、忙碌还是错误状态。心跳线程会定期检查每个设备的状态,如果发现设备离线,会尝试重新连接。同时,脚本还会监控设备的电量和温度,如果电量过低或温度过高,会自动暂停该设备上的任务,避免设备损坏。
def get_device_info(self):
"""获取设备详细信息"""
info = {}
info["device_id"] = self.device_id
info["status"] = self.status
info["battery_level"] = self.get_battery_level()
info["temperature"] = self.get_temperature()
info["current_task"] = self.current_task
info["last_heartbeat"] = datetime.fromtimestamp(self.last_heartbeat).strftime('%Y-%m-%d %H:%M:%S')
return info
def get_battery_level(self):
"""获取设备电池电量"""
result = self.execute_adb_command("shell dumpsys battery | grep level")
if result:
try:
level = int(result.split(':')[1].strip())
return level
except:
return None
return None
def get_temperature(self):
"""获取设备温度(摄氏度)"""
result = self.execute_adb_command("shell dumpsys battery | grep temperature")
if result:
try:
temp = int(result.split(':')[1].strip()) / 10
return temp
except:
return None
return None
def is_healthy(self):
"""检查设备是否健康(电量充足且温度正常)"""
battery = self.get_battery_level()
temp = self.get_temperature()
if battery is None or temp is None:
return False
if battery < 20:
logger.warning(f"设备{self.device_id}电量过低: {battery}%")
return False
if temp > 45:
logger.warning(f"设备{self.device_id}温度过高: {temp}°C")
return False
return True
def reconnect(self):
"""尝试重新连接设备"""
logger.info(f"尝试重新连接设备{self.device_id}")
# 先断开连接
subprocess.run(f'{CONFIG["adb_path"]} disconnect {self.device_id}', shell=True, capture_output=True)
time.sleep(2)
# 重新连接
subprocess.run(f'{CONFIG["adb_path"]} connect {self.device_id}', shell=True, capture_output=True)
time.sleep(3)
# 检查连接状态
return self.check_connection()
# 在DeviceManager类中添加设备健康检查
def heartbeat_loop(self):
while not self._stop_event.is_set():
try:
for device in self.devices.values():
if not device.check_connection():
logger.warning(f"设备{device.device_id}离线,尝试重连...")
device.retry_count += 1
if device.retry_count >= CONFIG["max_retry_times"]:
logger.error(f"设备{device.device_id}重连次数超过上限,标记为错误状态")
device.status = DEVICE_STATUS["ERROR"]
else:
# 检查设备健康状态
if not device.is_healthy():
device.status = DEVICE_STATUS["ERROR"]
logger.error(f"设备{device.device_id}健康状态不佳,标记为错误状态")
# 扫描新设备
self.scan_devices()
# 等待下一次心跳
for _ in range(30):
if self._stop_event.is_set():
break
time.sleep(1)
except Exception as e:
logger.error(f"心跳线程发生异常: {str(e)}")
time.sleep(5)
四、小红书APP统一启动与账号登录自动化
实现了设备的稳定连接之后,接下来就是小红书矩阵软件的核心功能之一:APP统一启动与账号登录自动化。手动启动数十台设备上的小红书APP是一项非常繁琐的工作,而且如果需要切换账号,工作量会更大。通过自动化脚本,我们可以实现一键启动所有设备上的小红书APP,并自动完成账号登录流程。
小红书的登录方式主要有手机号登录、微信登录和QQ登录。考虑到自动化操作的便利性,我推荐使用手机号+验证码的登录方式,因为微信和QQ登录需要跳转到对应的应用,操作流程更复杂,也更容易出现问题。脚本会自动输入手机号,然后等待用户输入验证码,或者对接第三方验证码平台自动获取验证码。为了提高登录的稳定性,脚本还会处理各种异常情况,比如网络错误、验证码错误、账号被限制登录等。
class XiaoHongShuAutomation:
"""小红书自动化操作类"""
def __init__(self, device):
self.device = device
self.package_name = "com.xingin.xhs"
self.activity_name = "com.xingin.xhs.activity.SplashActivity"
def start_app(self):
"""启动小红书APP"""
logger.info(f"设备{self.device.device_id}启动小红书APP")
# 先停止应用
self.stop_app()
time.sleep(1)
# 启动应用
self.device.execute_adb_command(f"shell am start -n {self.package_name}/{self.activity_name}")
time.sleep(5) # 等待应用启动
# 处理启动页广告
self._handle_splash_ad()
# 检查是否成功进入首页
if self._is_on_home_page():
logger.info(f"设备{self.device.device_id}小红书APP启动成功")
return True
else:
logger.error(f"设备{self.device.device_id}小红书APP启动失败")
return False
def stop_app(self):
"""停止小红书APP"""
self.device.execute_adb_command(f"shell am force-stop {self.package_name}")
time.sleep(1)
def _handle_splash_ad(self):
"""处理启动页广告"""
# 点击跳过广告按钮(坐标根据实际设备调整)
skip_button_x = 900
skip_button_y = 120
self.device.execute_adb_command(f"shell input tap {skip_button_x} {skip_button_y}")
time.sleep(1)
def _is_on_home_page(self):
"""判断是否在首页"""
# 检查首页特有的UI元素,这里通过截图分析颜色分布来简单判断
# 实际项目中可以使用OpenCV进行更精确的图像识别
screenshot_path = f"screenshot_{self.device.device_id}.png"
self.take_screenshot(screenshot_path)
if not os.path.exists(screenshot_path):
return False
try:
img = Image.open(screenshot_path)
# 检查首页底部导航栏的颜色
pixel = img.getpixel((500, 1900))
# 小红书底部导航栏选中状态为红色
if pixel[0] > 200 and pixel[1] < 100 and pixel[2] < 100:
os.remove(screenshot_path)
return True
else:
os.remove(screenshot_path)
return False
except Exception as e:
logger.error(f"判断首页状态失败: {str(e)}")
if os.path.exists(screenshot_path):
os.remove(screenshot_path)
return False
def take_screenshot(self, save_path):
"""截取设备屏幕"""
self.device.execute_adb_command(f"shell screencap -p /sdcard/screenshot.png")
self.device.execute_adb_command(f"pull /sdcard/screenshot.png {save_path}")
self.device.execute_adb_command(f"shell rm /sdcard/screenshot.png")
def login(self, phone_number, verify_code=None):
"""登录小红书账号"""
logger.info(f"设备{self.device.device_id}开始登录账号: {phone_number}")
# 点击"我的"进入个人中心
self.device.execute_adb_command("shell input tap 900 1900")
time.sleep(2)
# 点击"登录"按钮
self.device.execute_adb_command("shell input tap 500 1000")
time.sleep(2)
# 选择手机号登录
self.device.execute_adb_command("shell input tap 500 1200")
time.sleep(2)
# 输入手机号
self.device.execute_adb_command(f"shell input text {phone_number}")
time.sleep(1)
# 点击"获取验证码"
self.device.execute_adb_command("shell input tap 800 800")
time.sleep(1)
# 处理隐私协议弹窗
self.device.execute_adb_command("shell input tap 100 1400")
time.sleep(1)
# 再次点击"获取验证码"
self.device.execute_adb_command("shell input tap 800 800")
time.sleep(2)
# 如果提供了验证码,自动输入
if verify_code:
logger.info(f"设备{self.device.device_id}输入验证码: {verify_code}")
self.device.execute_adb_command(f"shell input text {verify_code}")
time.sleep(1)
# 点击"登录"
self.device.execute_adb_command("shell input tap 500 1000")
time.sleep(5)
# 检查登录是否成功
if self._is_logged_in():
logger.info(f"设备{self.device.device_id}账号登录成功")
return True
else:
logger.error(f"设备{self.device.device_id}账号登录失败")
return False
else:
logger.info(f"请在设备{self.device.device_id}上手动输入验证码并完成登录")
return False
def _is_logged_in(self):
"""判断是否已登录"""
# 点击"我的"
self.device.execute_adb_command("shell input tap 900 1900")
time.sleep(2)
# 截取个人中心页面
screenshot_path = f"login_check_{self.device.device_id}.png"
self.take_screenshot(screenshot_path)
if not os.path.exists(screenshot_path):
return False
try:
img = Image.open(screenshot_path)
# 检查是否显示用户名(通过检查特定位置的颜色)
# 实际项目中应使用更精确的OCR识别
pixel = img.getpixel((500, 500))
# 如果是登录状态,该位置应该是用户名(黑色文字)
if pixel[0] < 50 and pixel[1] < 50 and pixel[2] < 50:
os.remove(screenshot_path)
return True
else:
os.remove(screenshot_path)
return False
except Exception as e:
logger.error(f"判断登录状态失败: {str(e)}")
if os.path.exists(screenshot_path):
os.remove(screenshot_path)
return False
五、内容批量发布与互动操作脚本设计
内容批量发布是小红书矩阵软件最核心的功能,也是自动化脚本最复杂的部分。小红书的内容发布流程包括选择图片、编辑文字、添加话题、设置可见范围等多个步骤,每个步骤都需要精确的操作。同时,为了避免平台风控检测,不同设备的发布内容和操作时间应该有所差异,不能完全一致。
我设计的内容发布脚本支持批量上传图片和文字内容,并且可以为每个设备设置不同的发布时间和内容变体。脚本会自动将图片传输到设备上,然后模拟人工操作完成发布流程。除了内容发布,脚本还支持点赞、评论、关注等互动操作,这些操作可以帮助提升账号的活跃度和权重。所有的操作都会加入随机延迟,模拟真实用户的行为习惯。
def upload_image(self, local_image_path):
"""上传图片到设备"""
if not os.path.exists(local_image_path):
logger.error(f"图片文件不存在: {local_image_path}")
return None
# 压缩图片
compressed_path = f"compressed_{os.path.basename(local_image_path)}"
try:
img = Image.open(local_image_path)
img = img.convert('RGB')
img.save(compressed_path, quality=CONFIG["image_quality"])
except Exception as e:
logger.error(f"图片压缩失败: {str(e)}")
return None
# 上传到设备
remote_path = f"/sdcard/Pictures/{os.path.basename(compressed_path)}"
result = self.device.execute_adb_command(f"push {compressed_path} {remote_path}")
# 删除本地压缩文件
if os.path.exists(compressed_path):
os.remove(compressed_path)
if result:
logger.info(f"图片上传成功: {local_image_path} -> {remote_path}")
return remote_path
else:
logger.error(f"图片上传失败: {local_image_path}")
return None
def post_content(self, image_paths, title, content, tags=None):
"""发布小红书笔记"""
logger.info(f"设备{self.device.device_id}开始发布笔记")
if not self._is_logged_in():
logger.error(f"设备{self.device.device_id}未登录,无法发布内容")
return False
# 上传所有图片
remote_image_paths = []
for path in image_paths:
remote_path = self.upload_image(path)
if remote_path:
remote_image_paths.append(remote_path)
else:
logger.error(f"设备{self.device.device_id}图片上传失败,取消发布")
return False
if not remote_image_paths:
logger.error(f"设备{self.device.device_id}没有可用的图片,取消发布")
return False
# 点击"+"号发布按钮
self.device.execute_adb_command("shell input tap 500 1900")
time.sleep(2)
# 选择"从相册选择"
self.device.execute_adb_command("shell input tap 500 1500")
time.sleep(2)
# 选择图片(这里只选择第一张,实际可以选择多张)
self.device.execute_adb_command("shell input tap 150 300")
time.sleep(1)
# 点击"下一步"
self.device.execute_adb_command("shell input tap 900 100")
time.sleep(3)
# 再次点击"下一步"
self.device.execute_adb_command("shell input tap 900 100")
time.sleep(3)
# 输入标题
self.device.execute_adb_command("shell input tap 500 200")
time.sleep(1)
self._input_text_with_delay(title)
time.sleep(1)
# 输入内容
self.device.execute_adb_command("shell input tap 500 400")
time.sleep(1)
self._input_text_with_delay(content)
time.sleep(1)
# 添加话题
if tags and isinstance(tags, list):
for tag in tags:
self.device.execute_adb_command("shell input text #")
time.sleep(0.5)
self._input_text_with_delay(tag)
time.sleep(0.5)
# 选择第一个话题建议
self.device.execute_adb_command("shell input tap 200 500")
time.sleep(0.5)
# 随机等待一段时间,模拟编辑过程
time.sleep(random.randint(10, 30))
# 点击"发布"
self.device.execute_adb_command("shell input tap 900 100")
time.sleep(5)
# 检查是否发布成功
if self._is_post_successful():
logger.info(f"设备{self.device.device_id}笔记发布成功")
return True
else:
logger.error(f"设备{self.device.device_id}笔记发布失败")
return False
def _input_text_with_delay(self, text):
"""带延迟输入文本,模拟真人打字"""
for char in text:
self.device.execute_adb_command(f"shell input text '{char}'")
time.sleep(random.uniform(0.1, 0.3))
def _is_post_successful(self):
"""判断笔记是否发布成功"""
# 检查是否回到首页
if self._is_on_home_page():
# 进入个人中心查看最新笔记
self.device.execute_adb_command("shell input tap 900 1900")
time.sleep(2)
# 点击"笔记"标签
self.device.execute_adb_command("shell input tap 300 1200")
time.sleep(2)
# 检查是否有新笔记
screenshot_path = f"post_check_{self.device.device_id}.png"
self.take_screenshot(screenshot_path)
if os.path.exists(screenshot_path):
os.remove(screenshot_path)
return True
return False
def like_post(self, post_index=0):
"""点赞笔记"""
logger.info(f"设备{self.device.device_id}点赞第{post_index+1}条笔记")
if not self._is_on_home_page():
self.start_app()
# 点击第一条笔记
self.device.execute_adb_command("shell input tap 500 500")
time.sleep(2)
# 点击点赞按钮
self.device.execute_adb_command("shell input tap 900 1200")
time.sleep(1)
# 返回首页
self.device.execute_adb_command("shell input keyevent 4")
time.sleep(1)
logger.info(f"设备{self.device.device_id}点赞完成")
return True
def comment_post(self, comment_content):
"""评论笔记"""
logger.info(f"设备{self.device.device_id}评论笔记: {comment_content}")
if not self._is_on_home_page():
self.start_app()
# 点击第一条笔记
self.device.execute_adb_command("shell input tap 500 500")
time.sleep(2)
# 点击评论按钮
self.device.execute_adb_command("shell input tap 900 1400")
time.sleep(2)
# 输入评论内容
self.device.execute_adb_command("shell input tap 500 1800")
time.sleep(1)
self._input_text_with_delay(comment_content)
time.sleep(1)
# 点击发送
self.device.execute_adb_command("shell input tap 900 1800")
time.sleep(2)
# 返回首页
self.device.execute_adb_command("shell input keyevent 4")
time.sleep(1)
self.device.execute_adb_command("shell input keyevent 4")
time.sleep(1)
logger.info(f"设备{self.device.device_id}评论完成")
return True
六、多设备任务调度与负载均衡实现
当管理的设备数量较多时,如何合理地分配任务、避免设备过载,是小红书矩阵软件需要解决的重要问题。如果所有设备同时执行任务,不仅会导致网络拥堵,还会增加被平台检测到的风险。因此,我们需要一个高效的任务调度系统,能够根据设备的状态和负载情况,智能地分配任务。
我设计的任务调度系统采用了生产者 - 消费者模式,所有的任务都被放入一个任务队列中,然后由多个工作线程从队列中取出任务并执行。每个工作线程对应一个设备,当设备完成一个任务后,会自动从队列中获取下一个任务。任务调度系统还会考虑设备的健康状态和历史执行情况,优先将任务分配给性能更好、稳定性更高的设备。同时,系统会限制同时执行的任务数量,避免网络和系统资源耗尽。
class Task:
"""任务类"""
def __init__(self, task_type, params=None, priority=5):
self.task_id = f"task_{int(time.time()*1000)}_{random.randint(1000, 9999)}"
self.task_type = task_type
self.params = params or {}
self.priority = priority # 优先级,1-10,数字越小优先级越高
self.status = "pending"
self.create_time = time.time()
self.start_time = None
self.end_time = None
self.result = None
self.device_id = None
def to_dict(self):
return {
"task_id": self.task_id,
"task_type": self.task_type,
"params": self.params,
"priority": self.priority,
"status": self.status,
"create_time": datetime.fromtimestamp(self.create_time).strftime('%Y-%m-%d %H:%M:%S'),
"start_time": datetime.fromtimestamp(self.start_time).strftime('%Y-%m-%d %H:%M:%S') if self.start_time else None,
"end_time": datetime.fromtimestamp(self.end_time).strftime('%Y-%m-%d %H:%M:%S') if self.end_time else None,
"result": self.result,
"device_id": self.device_id
}
class TaskScheduler:
"""任务调度器"""
def __init__(self, device_manager):
self.device_manager = device_manager
self.task_queue = []
self.completed_tasks = []
self.failed_tasks = []
self._lock = threading.Lock()
self._stop_event = threading.Event()
self._worker_threads = []
def add_task(self, task):
"""添加任务到队列"""
with self._lock:
# 按优先级插入队列
inserted = False
for i, t in enumerate(self.task_queue):
if task.priority < t.priority:
self.task_queue.insert(i, task)
inserted = True
break
if not inserted:
self.task_queue.append(task)
logger.info(f"任务{task.task_id}已添加到队列,当前队列长度: {len(self.task_queue)}")
def add_tasks(self, tasks):
"""批量添加任务"""
for task in tasks:
self.add_task(task)
def get_next_task(self):
"""获取下一个待执行的任务"""
with self._lock:
if self.task_queue:
task = self.task_queue.pop(0)
task.status = "running"
return task
return None
def complete_task(self, task, success, result=None):
"""标记任务完成"""
with self._lock:
task.status = "completed" if success else "failed"
task.end_time = time.time()
task.result = result
if success:
self.completed_tasks.append(task)
logger.info(f"任务{task.task_id}执行成功")
else:
self.failed_tasks.append(task)
logger.error(f"任务{task.task_id}执行失败: {result}")
def start(self):
"""启动任务调度器"""
logger.info("任务调度器已启动")
# 启动工作线程
for i in range(CONFIG["max_concurrent_tasks"]):
worker_thread = threading.Thread(target=self._worker_loop, args=(i,), daemon=True)
self._worker_threads.append(worker_thread)
worker_thread.start()
logger.info(f"已启动{CONFIG['max_concurrent_tasks']}个工作线程")
def stop(self):
"""停止任务调度器"""
logger.info("正在停止任务调度器...")
self._stop_event.set()
for thread in self._worker_threads:
if thread.is_alive():
thread.join()
logger.info("任务调度器已停止")
def _worker_loop(self, worker_id):
"""工作线程循环"""
logger.info(f"工作线程{worker_id}已启动")
while not self._stop_event.is_set():
try:
# 获取可用设备
available_devices = self.device_manager.get_available_devices()
if not available_devices:
time.sleep(5)
continue
# 获取下一个任务
task = self.get_next_task()
if not task:
time.sleep(5)
continue
# 选择一个可用设备
device = random.choice(available_devices)
device.status = DEVICE_STATUS["BUSY"]
device.current_task = task.task_id
task.device_id = device.device_id
task.start_time = time.time()
logger.info(f"工作线程{worker_id}分配设备{device.device_id}执行任务{task.task_id}")
# 执行任务
success, result = self._execute_task(device, task)
# 标记任务完成
self.complete_task(task, success, result)
# 释放设备
device.status = DEVICE_STATUS["ONLINE"]
device.current_task = None
# 任务间隔
time.sleep(random.uniform(*CONFIG["task_interval"]))
except Exception as e:
logger.error(f"工作线程{worker_id}发生异常: {str(e)}")
time.sleep(5)
logger.info(f"工作线程{worker_id}已停止")
def _execute_task(self, device, task):
"""执行具体任务"""
try:
xhs = XiaoHongShuAutomation(device)
if task.task_type == TASK_TYPE["START_APP"]:
success = xhs.start_app()
return success, "启动成功" if success else "启动失败"
elif task.task_type == TASK_TYPE["LOGIN"]:
phone = task.params.get("phone")
code = task.params.get("code")
if not phone:
return False, "缺少手机号参数"
success = xhs.login(phone, code)
return success, "登录成功" if success else "登录失败"
elif task.task_type == TASK_TYPE["POST_CONTENT"]:
images = task.params.get("images", [])
title = task.params.get("title", "")
content = task.params.get("content", "")
tags = task.params.get("tags", [])
if not images or not title:
return False, "缺少图片或标题参数"
success = xhs.post_content(images, title, content, tags)
return success, "发布成功" if success else "发布失败"
elif task.task_type == TASK_TYPE["LIKE"]:
success = xhs.like_post()
return success, "点赞成功" if success else "点赞失败"
elif task.task_type == TASK_TYPE["COMMENT"]:
content = task.params.get("content", "")
if not content:
return False, "缺少评论内容参数"
success = xhs.comment_post(content)
return success, "评论成功" if success else "评论失败"
else:
return False, f"未知任务类型: {task.task_type}"
except Exception as e:
logger.error(f"执行任务{task.task_id}发生异常: {str(e)}")
return False, f"执行异常: {str(e)}"
def get_task_status(self):
"""获取任务状态统计"""
with self._lock:
return {
"pending": len(self.task_queue),
"running": CONFIG["max_concurrent_tasks"] - len(self.device_manager.get_available_devices()),
"completed": len(self.completed_tasks),
"failed": len(self.failed_tasks)
}
# 初始化任务调度器
task_scheduler = TaskScheduler(device_manager)
七、风控规避与行为模拟优化策略
在小红书矩阵软件的运营过程中,风控规避是一个永恒的话题。平台会通过分析用户的行为模式、设备信息、IP地址等多个维度来检测自动化操作。如果脚本的行为过于机械和规律,很容易被平台检测到,导致账号被限流甚至封禁。因此,我们需要在脚本中加入各种风控规避措施,尽可能模拟真实用户的行为习惯。
我总结了几个有效的风控规避策略:首先是操作时间的随机化,所有的点击、滑动、输入操作都应该加入随机延迟,避免精确到毫秒的重复操作。其次是行为路径的多样化,不要每次都按照完全相同的路径执行任务,可以加入一些随机的浏览和滑动操作。第三是内容的差异化,不同账号发布的内容应该有所不同,即使是相同的主题,也要修改标题、内容和图片。第四是设备信息的伪装,修改设备的IMEI、MAC地址、系统版本等信息,避免平台通过设备指纹识别批量账号。
class RiskControl:
"""风控控制类"""
@staticmethod
def random_sleep(min_seconds, max_seconds):
"""随机睡眠"""
time.sleep(random.uniform(min_seconds, max_seconds))
@staticmethod
def random_swipe(device, start_x_range, start_y_range, end_x_range, end_y_range, duration_range=(200, 500)):
"""随机滑动"""
start_x = random.randint(*start_x_range)
start_y = random.randint(*start_y_range)
end_x = random.randint(*end_x_range)
end_y = random.randint(*end_y_range)
duration = random.randint(*duration_range)
device.execute_adb_command(f"shell input swipe {start_x} {start_y} {end_x} {end_y} {duration}")
@staticmethod
def random_tap(device, x_range, y_range):
"""随机点击"""
x = random.randint(*x_range)
y = random.randint(*y_range)
device.execute_adb_command(f"shell input tap {x} {y}")
@staticmethod
def simulate_browsing(device, duration_min=30, duration_max=120):
"""模拟浏览行为"""
logger.info(f"设备{device.device_id}开始模拟浏览")
start_time = time.time()
duration = random.randint(duration_min, duration_max)
while time.time() - start_time < duration:
# 随机滑动
RiskControl.random_swipe(device, (400, 600), (1500, 1700), (400, 600), (300, 500), (300, 800))
RiskControl.random_sleep(2, 8)
# 随机点击进入笔记
if random.random() < 0.3:
RiskControl.random_tap(device, (100, 900), (300, 1500))
RiskControl.random_sleep(3, 10)
# 随机滑动浏览笔记内容
for _ in range(random.randint(1, 5)):
RiskControl.random_swipe(device, (400, 600), (1500, 1700), (400, 600), (300, 500), (300, 800))
RiskControl.random_sleep(1, 5)
# 随机点赞
if random.random() < 0.5:
RiskControl.random_tap(device, (850, 950), (1150, 1250))
RiskControl.random_sleep(1, 3)
# 返回首页
device.execute_adb_command("shell input keyevent 4")
RiskControl.random_sleep(1, 3)
logger.info(f"设备{device.device_id}模拟浏览结束")
@staticmethod
def modify_device_info(device):
"""修改设备信息(需要root权限)"""
# 注意:此功能需要设备root才能使用
logger.info(f"设备{device.device_id}开始修改设备信息")
# 生成随机IMEI
imei = ''.join([str(random.randint(0, 9)) for _ in range(15)])
device.execute_adb_command(f"shell su -c 'settings put secure android_id {imei}'")
# 生成随机MAC地址
mac = ':'.join(['%02x' % random.randint(0, 255) for _ in range(6)])
device.execute_adb_command(f"shell su -c 'ip link set wlan0 address {mac}'")
# 修改系统版本
device.execute_adb_command(f"shell su -c 'setprop ro.build.version.release {random.randint(10, 13)}'")
logger.info(f"设备{device.device_id}设备信息修改完成")
# 在XiaoHongShuAutomation类中集成风控控制
def post_content(self, image_paths, title, content, tags=None):
"""发布小红书笔记(增强版,加入风控控制)"""
logger.info(f"设备{self.device.device_id}开始发布笔记")
if not self._is_logged_in():
logger.error(f"设备{self.device.device_id}未登录,无法发布内容")
return False
# 发布前模拟浏览
RiskControl.simulate_browsing(self.device, 60, 180)
# 上传所有图片
remote_image_paths = []
for path in image_paths:
remote_path = self.upload_image(path)
if remote_path:
remote_image_paths.append(remote_path)
else:
logger.error(f"设备{self.device.device_id}图片上传失败,取消发布")
return False
if not remote_image_paths:
logger.error(f"设备{self.device.device_id}没有可用的图片,取消发布")
return False
# 点击"+"号发布按钮
RiskControl.random_tap(self.device, (450, 550), (1850, 1950))
RiskControl.random_sleep(2, 4)
# 选择"从相册选择"
RiskControl.random_tap(self.device, (450, 550), (1450, 1550))
RiskControl.random_sleep(2, 4)
# 选择图片
RiskControl.random_tap(self.device, (100, 200), (250, 350))
RiskControl.random_sleep(1, 2)
# 点击"下一步"
RiskControl.random_tap(self.device, (850, 950), (50, 150))
RiskControl.random_sleep(3, 5)
# 再次点击"下一步"
RiskControl.random_tap(self.device, (850, 950), (50, 150))
RiskControl.random_sleep(3, 5)
# 输入标题
RiskControl.random_tap(self.device, (450, 550), (150, 250))
RiskControl.random_sleep(1, 2)
self._input_text_with_delay(title)
RiskControl.random_sleep(1, 3)
# 输入内容
RiskControl.random_tap(self.device, (450, 550), (350, 450))
RiskControl.random_sleep(1, 2)
self._input_text_with_delay(content)
RiskControl.random_sleep(1, 3)
# 添加话题
if tags and isinstance(tags, list):
for tag in tags:
self.device.execute_adb_command("shell input text #")
RiskControl.random_sleep(0.3, 0.7)
self._input_text_with_delay(tag)
RiskControl.random_sleep(0.3, 0.7)
RiskControl.random_tap(self.device, (150, 250), (450, 550))
RiskControl.random_sleep(0.3, 0.7)
# 随机等待一段时间,模拟编辑过程
RiskControl.random_sleep(15, 45)
# 点击"发布"
RiskControl.random_tap(self.device, (850, 950), (50, 150))
RiskControl.random_sleep(5, 10)
# 检查是否发布成功
if self._is_post_successful():
logger.info(f"设备{self.device.device_id}笔记发布成功")
# 发布后继续模拟浏览
RiskControl.simulate_browsing(self.device, 30, 90)
return True
else:
logger.error(f"设备{self.device.device_id}笔记发布失败")
return False
八、脚本性能监控与日志系统搭建
一个完善的小红书矩阵软件不仅需要功能强大的自动化脚本,还需要完善的性能监控和日志系统。通过监控脚本的运行状态,我们可以及时发现和解决问题,保证整个系统的稳定运行。日志系统则可以帮助我们记录所有的操作和异常情况,便于后期的问题排查和分析。
我在脚本中集成了Python的logging模块,用于记录系统运行日志。日志分为不同的级别,包括DEBUG、INFO、WARNING、ERROR和CRITICAL,不同级别的日志会被记录到不同的文件中。同时,脚本还提供了一个简单的Web界面,用于实时监控设备状态、任务执行情况和系统性能指标。通过这个界面,我们可以直观地看到整个系统的运行状态,及时发现异常设备和失败任务。
class SystemMonitor:
"""系统监控类"""
def __init__(self, device_manager, task_scheduler):
self.device_manager = device_manager
self.task_scheduler = task_scheduler
self._stop_event = threading.Event()
self._monitor_thread = None
def start(self):
"""启动系统监控"""
logger.info("系统监控已启动")
def monitor_loop():
while not self._stop_event.is_set():
try:
# 获取设备状态
devices_info = []
for device in self.device_manager.devices.values():
devices_info.append(device.get_device_info())
# 获取任务状态
task_status = self.task_scheduler.get_task_status()
# 记录系统状态
logger.info(f"系统状态 - 设备总数: {len(devices_info)}, 在线设备: {len([d for d in devices_info if d['status'] == 'online'])}, "
f"待执行任务: {task_status['pending']}, 执行中: {task_status['running']}, "
f"已完成: {task_status['completed']}, 失败: {task_status['failed']}")
# 检查异常设备
error_devices = [d for d in devices_info if d['status'] == 'error']
if error_devices:
logger.warning(f"发现{len(error_devices)}个异常设备: {[d['device_id'] for d in error_devices]}")
# 检查失败任务
if task_status['failed'] > 0:
logger.warning(f"发现{task_status['failed']}个失败任务")
# 保存状态到文件
status_data = {
"timestamp": datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
"devices": devices_info,
"tasks": task_status
}
with open("system_status.json", "w", encoding="utf-8") as f:
json.dump(status_data, f, ensure_ascii=False, indent=2)
# 等待下一次监控
for _ in range(60):
if self._stop_event.is_set():
break
time.sleep(1)
except Exception as e:
logger.error(f"系统监控线程发生异常: {str(e)}")
time.sleep(5)
self._monitor_thread = threading.Thread(target=monitor_loop, daemon=True)
self._monitor_thread.start()
def stop(self):
"""停止系统监控"""
logger.info("正在停止系统监控...")
self._stop_event.set()
if self._monitor_thread and self._monitor_thread.is_alive():
self._monitor_thread.join()
logger.info("系统监控已停止")
# 主函数
def main():
try:
# 初始化设备管理器
device_manager.scan_devices()
device_manager.start_heartbeat()
# 初始化任务调度器
task_scheduler.start()
# 初始化系统监控
system_monitor = SystemMonitor(device_manager, task_scheduler)
system_monitor.start()
logger.info("小红书矩阵自动化系统已启动")
logger.info("输入 'help' 查看可用命令")
# 命令行交互
while True:
try:
command = input("> ").strip()
if command == "exit":
break
elif command == "help":
print("可用命令:")
print(" devices - 查看设备列表")
print(" tasks - 查看任务状态")
print(" add_task - 添加任务")
print(" clear_failed - 清除失败任务")
print(" exit - 退出系统")
elif command == "devices":
devices = device_manager.devices.values()
print(f"设备总数: {len(devices)}")
for device in devices:
info = device.get_device_info()
print(f" {info['device_id']} - {info['status']} - 电量: {info['battery_level']}% - 温度: {info['temperature']}°C")
elif command == "tasks":
status = task_scheduler.get_task_status()
print(f"待执行任务: {status['pending']}")
print(f"执行中: {status['running']}")
print(f"已完成: {status['completed']}")
print(f"失败: {status['failed']}")
elif command == "add_task":
print("选择任务类型:")
print("1. 启动APP")
print("2. 登录账号")
print("3. 发布内容")
print("4. 点赞")
print("5. 评论")
choice = input("请输入任务类型编号: ").strip()
if choice == "1":
task = Task(TASK_TYPE["START_APP"])
task_scheduler.add_task(task)
print(f"已添加启动APP任务,任务ID: {task.task_id}")
elif choice == "2":
phone = input("请输入手机号: ").strip()
code = input("请输入验证码(留空则手动输入): ").strip() or None
task = Task(TASK_TYPE["LOGIN"], {"phone": phone, "code": code})
task_scheduler.add_task(task)
print(f"已添加登录任务,任务ID: {task.task_id}")
elif choice == "3":
images = input("请输入图片路径(多个用逗号分隔): ").strip().split(',')
images = [img.strip() for img in images if img.strip()]
title = input("请输入标题: ").strip()
content = input("请输入内容: ").strip()
tags = input("请输入话题(多个用逗号分隔): ").strip().split(',')
tags = [tag.strip() for tag in tags if tag.strip()]
task = Task(TASK_TYPE["POST_CONTENT"], {
"images": images,
"title": title,
"content": content,
"tags": tags
})
task_scheduler.add_task(task)
print(f"已添加发布任务,任务ID: {task.task_id}")
elif choice == "4":
task = Task(TASK_TYPE["LIKE"])
task_scheduler.add_task(task)
print(f"已添加点赞任务,任务ID: {task.task_id}")
elif choice == "5":
content = input("请输入评论内容: ").strip()
task = Task(TASK_TYPE["COMMENT"], {"content": content})
task_scheduler.add_task(task)
print(f"已添加评论任务,任务ID: {task.task_id}")
else:
print("无效的任务类型编号")
elif command == "clear_failed":
task_scheduler.failed_tasks.clear()
print("已清除所有失败任务")
else:
print("未知命令,输入 'help' 查看可用命令")
except KeyboardInterrupt:
break
except Exception as e:
logger.error(f"命令执行发生异常: {str(e)}")
except Exception as e:
logger.error(f"系统启动失败: {str(e)}")
finally:
# 停止所有服务
system_monitor.stop()
task_scheduler.stop()
device_manager.stop()
logger.info("小红书矩阵自动化系统已停止")
if __name__ == "__main__":
main()
以上就是一套完整的小红书矩阵软件多设备批量管理自动化脚本。这套脚本基于Python和ADB协议开发,实现了设备连接、账号登录、内容发布、互动操作等全流程自动化。通过完善的任务调度系统和风控规避策略,脚本能够稳定管理大量设备,同时有效降低被平台检测到的风险。
在实际使用过程中,你可以根据自己的需求对脚本进行修改和扩展,比如添加更多的操作类型、优化图像识别精度、集成第三方验证码平台等。希望这篇文章能够帮助你提升小红书矩阵运营的效率,减少人工成本。