feat: publish workphone SDK deployment and API docs
This commit is contained in:
158
sdk/agent/anti_ban/touch_hardener.py
Normal file
158
sdk/agent/anti_ban/touch_hardener.py
Normal file
@@ -0,0 +1,158 @@
|
||||
"""
|
||||
触摸加固层 — 将机器精确操作伪装为真人触摸
|
||||
|
||||
功能:
|
||||
1. 坐标随机偏移 (+-3~8px)
|
||||
2. 点击时长随机化 (50~150ms)
|
||||
3. 贝塞尔曲线轨迹滑动 (替代直线滑动)
|
||||
4. 按压-微移-抬起时序模拟
|
||||
5. 可配置的「手抖」程度
|
||||
"""
|
||||
|
||||
import logging
|
||||
import math
|
||||
import random
|
||||
import time
|
||||
from typing import List, Optional, Tuple
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
Point = Tuple[float, float]
|
||||
|
||||
|
||||
class TouchHardener:
|
||||
"""触摸事件加固 — 让自动化操作看起来像人"""
|
||||
|
||||
def __init__(self, device=None, tremor_level: float = 1.0):
|
||||
"""
|
||||
Args:
|
||||
device: uiautomator2 设备对象
|
||||
tremor_level: 手抖程度倍数 (0.5=稳手, 1.0=普通, 2.0=抖得厉害)
|
||||
"""
|
||||
self.d = device
|
||||
self.tremor = max(0.1, tremor_level)
|
||||
|
||||
def humanized_click(self, x: int, y: int) -> Tuple[int, int]:
|
||||
"""
|
||||
带随机偏移的点击。返回实际点击坐标。
|
||||
"""
|
||||
offset_x = random.gauss(0, 3 * self.tremor)
|
||||
offset_y = random.gauss(0, 3 * self.tremor)
|
||||
actual_x = max(0, int(x + offset_x))
|
||||
actual_y = max(0, int(y + offset_y))
|
||||
|
||||
duration_ms = random.randint(50, 150)
|
||||
|
||||
if self.d:
|
||||
self.d.click(actual_x, actual_y)
|
||||
|
||||
settle_ms = random.uniform(30, 80)
|
||||
time.sleep(settle_ms / 1000)
|
||||
|
||||
logger.debug(f"click ({x},{y}) → ({actual_x},{actual_y}) dur={duration_ms}ms")
|
||||
return actual_x, actual_y
|
||||
|
||||
def humanized_swipe(self, x1: int, y1: int, x2: int, y2: int,
|
||||
duration: float = 0.5, steps: int = 0) -> List[Point]:
|
||||
"""
|
||||
贝塞尔曲线滑动。返回轨迹点序列。
|
||||
"""
|
||||
sx = x1 + random.gauss(0, 2 * self.tremor)
|
||||
sy = y1 + random.gauss(0, 2 * self.tremor)
|
||||
ex = x2 + random.gauss(0, 2 * self.tremor)
|
||||
ey = y2 + random.gauss(0, 2 * self.tremor)
|
||||
|
||||
ctrl_points = self._random_bezier_controls(sx, sy, ex, ey)
|
||||
|
||||
if steps <= 0:
|
||||
dist = math.hypot(ex - sx, ey - sy)
|
||||
steps = max(8, int(dist / 15))
|
||||
|
||||
trajectory = self._bezier_curve(sx, sy, ex, ey, ctrl_points, steps)
|
||||
|
||||
if self.d:
|
||||
self.d.swipe(int(sx), int(sy), int(ex), int(ey), duration=duration, steps=steps)
|
||||
|
||||
logger.debug(f"swipe ({x1},{y1})→({x2},{y2}) pts={len(trajectory)}")
|
||||
return trajectory
|
||||
|
||||
def humanized_long_press(self, x: int, y: int, duration_ms: int = 800):
|
||||
"""长按 — 带起始微抖"""
|
||||
actual_x = int(x + random.gauss(0, 2 * self.tremor))
|
||||
actual_y = int(y + random.gauss(0, 2 * self.tremor))
|
||||
actual_dur = duration_ms + random.randint(-100, 150)
|
||||
actual_dur = max(300, actual_dur)
|
||||
|
||||
if self.d:
|
||||
self.d.long_click(actual_x, actual_y, duration=actual_dur / 1000)
|
||||
|
||||
logger.debug(f"long_press ({x},{y})→({actual_x},{actual_y}) dur={actual_dur}ms")
|
||||
|
||||
def humanized_type(self, text: str, char_delay_range: Tuple[float, float] = (0.03, 0.12)):
|
||||
"""
|
||||
逐字输入 — 每个字符间隔随机延迟,模拟打字节奏。
|
||||
"""
|
||||
for i, char in enumerate(text):
|
||||
if self.d:
|
||||
self.d.send_keys(char)
|
||||
delay = random.uniform(*char_delay_range)
|
||||
if char in (' ', ',', '.', '。', ','):
|
||||
delay *= random.uniform(1.5, 3.0)
|
||||
time.sleep(delay)
|
||||
logger.debug(f"typed {len(text)} chars")
|
||||
|
||||
def pre_action_pause(self):
|
||||
"""操作前的微停顿 — 模拟人的反应时间"""
|
||||
pause = random.uniform(0.2, 0.8) * self.tremor
|
||||
time.sleep(pause)
|
||||
|
||||
def post_action_pause(self):
|
||||
"""操作后的短暂停顿 — 模拟人看结果"""
|
||||
pause = random.uniform(0.3, 1.2) * self.tremor
|
||||
time.sleep(pause)
|
||||
|
||||
# ---- 内部方法 ----
|
||||
|
||||
@staticmethod
|
||||
def _random_bezier_controls(x1: float, y1: float,
|
||||
x2: float, y2: float) -> List[Point]:
|
||||
"""生成 1~2 个随机控制点,使路径弯曲"""
|
||||
mx = (x1 + x2) / 2
|
||||
my = (y1 + y2) / 2
|
||||
dist = math.hypot(x2 - x1, y2 - y1)
|
||||
spread = dist * random.uniform(0.1, 0.35)
|
||||
|
||||
c1 = (mx + random.gauss(0, spread), my + random.gauss(0, spread))
|
||||
|
||||
if random.random() > 0.5:
|
||||
c2 = (mx + random.gauss(0, spread * 0.6), my + random.gauss(0, spread * 0.6))
|
||||
return [c1, c2]
|
||||
return [c1]
|
||||
|
||||
@staticmethod
|
||||
def _bezier_curve(x1: float, y1: float, x2: float, y2: float,
|
||||
controls: List[Point], steps: int) -> List[Point]:
|
||||
"""计算贝塞尔曲线点"""
|
||||
points: List[Point] = []
|
||||
if len(controls) == 1:
|
||||
cx, cy = controls[0]
|
||||
for i in range(steps + 1):
|
||||
t = i / steps
|
||||
bx = (1 - t) ** 2 * x1 + 2 * (1 - t) * t * cx + t ** 2 * x2
|
||||
by = (1 - t) ** 2 * y1 + 2 * (1 - t) * t * cy + t ** 2 * y2
|
||||
points.append((bx, by))
|
||||
elif len(controls) >= 2:
|
||||
c1x, c1y = controls[0]
|
||||
c2x, c2y = controls[1]
|
||||
for i in range(steps + 1):
|
||||
t = i / steps
|
||||
bx = ((1 - t) ** 3 * x1 + 3 * (1 - t) ** 2 * t * c1x +
|
||||
3 * (1 - t) * t ** 2 * c2x + t ** 3 * x2)
|
||||
by = ((1 - t) ** 3 * y1 + 3 * (1 - t) ** 2 * t * c1y +
|
||||
3 * (1 - t) * t ** 2 * c2y + t ** 3 * y2)
|
||||
points.append((bx, by))
|
||||
else:
|
||||
for i in range(steps + 1):
|
||||
t = i / steps
|
||||
points.append((x1 + (x2 - x1) * t, y1 + (y2 - y1) * t))
|
||||
return points
|
||||
Reference in New Issue
Block a user