"""拟人行为模拟 使用高斯分布随机延迟、偶尔长休息、工作时间限制等策略, 模拟真人操作节奏,降低被检测风险。 """ import logging import random import time from .config import Config logger = logging.getLogger("wechat_clicker.human_like") class HumanBehavior: """拟人行为引擎""" def __init__(self, config: Config): self.config = config self._cycle_count = 0 self._break_probability = 0.05 # 5% 概率触发长休息 self._break_min = 30 self._break_max = 120 def delay(self, delay_name: str): """执行指定名称的随机延迟。""" seconds = self.config.get_delay(delay_name) logger.debug(f"延迟 {delay_name}: {seconds:.1f}s") time.sleep(seconds) def random_delay(self, min_s: float, max_s: float): """执行指定范围内的随机延迟(高斯分布)。""" mid = (min_s + max_s) / 2 std = (max_s - min_s) / 4 value = random.gauss(mid, std) value = max(min_s, min(max_s, value)) time.sleep(value) def micro_jitter(self): """极短延迟(0.1-0.5 秒),用于连续操作之间。""" time.sleep(random.uniform(0.1, 0.5)) def scan_interval_with_jitter(self) -> float: """返回带 ±20% 抖动的扫描间隔时间(秒)。""" base = self.config.scan_interval jitter = base * 0.2 return random.uniform(base - jitter, base + jitter) # ---------------------------------------------------------------- # 长休息 # ---------------------------------------------------------------- def should_take_break(self) -> bool: """判断是否应该触发一次长休息。 每个循环有固定概率触发,模拟真人偶尔离开电脑。 """ self._cycle_count += 1 return random.random() < self._break_probability def long_break(self): """执行一次长休息(30-120 秒)。""" duration = random.uniform(self._break_min, self._break_max) logger.info(f"模拟长休息: {duration:.0f}s") time.sleep(duration) # ---------------------------------------------------------------- # 工作时间 # ---------------------------------------------------------------- def is_off_hours(self) -> bool: """检查是否在非工作时间(应暂停操作)。""" return not self.config.is_within_working_hours() # ---------------------------------------------------------------- # 随机子集 # ---------------------------------------------------------------- def random_subset_count(self, total: int, max_count: int) -> int: """决定本次处理多少个项目。 不总是处理 max_count 个,偶尔少处理一些,模拟真人不会每次都处理所有内容。 """ if total <= 0: return 0 upper = min(total, max_count) # 80% 概率处理全部(上限内),20% 概率减少 1-2 个 if random.random() < 0.8: return upper return max(1, upper - random.randint(1, 2))