Bladeren bron

feat: update

jerry 1 week geleden
bovenliggende
commit
4025b4fc3c
2 gewijzigde bestanden met toevoegingen van 155 en 41 verwijderingen
  1. 30 2
      plugins/tls_plugin.py
  2. 125 39
      utils/mouse.py

+ 30 - 2
plugins/tls_plugin.py

@@ -87,12 +87,40 @@ class TlsPlugin(IVSPlg):
         
         
     def keep_alive(self):
     def keep_alive(self):
         try:
         try:
-            resp = self._perform_request("GET", self.page.url, retry_count=1)
-            self._check_page_is_session_expired_or_invalid('Book your appointment', html = resp.text)
+            self.page.refresh()
+            self.page.wait.load_start(timeout=2)
+            self.page.wait.doc_loaded()
+            time.sleep(random.uniform(1, 3))
+            self._check_page_is_session_expired_or_invalid('Book your appointment', html = self.page.html)
+            self.simulate_random_human_clicks()
         except SessionExpiredOrInvalidError as e:
         except SessionExpiredOrInvalidError as e:
             self.is_healthy = False
             self.is_healthy = False
         except Exception as e:
         except Exception as e:
             self._log(f"Unexpected error in keep_alive: {e}")
             self._log(f"Unexpected error in keep_alive: {e}")
+            
+    def simulate_random_human_clicks(self, min_x=300, max_x=800, min_y=400, max_y=600, min_clicks=1, max_clicks=2):
+        """
+        在指定区域内模拟人类随机移动鼠标并点击数次。
+        
+        :param min_x: X坐标最小范围
+        :param max_x: X坐标最大范围
+        :param min_y: Y坐标最小范围
+        :param max_y: Y坐标最大范围
+        :param min_clicks: 随便点击的最少次数
+        :param max_clicks: 随便点击的最多次数
+        """
+        click_count = random.randint(min_clicks, max_clicks)
+        self._log(f"Starting random human simulation: will click {click_count} times in the area.")
+        for i in range(click_count):
+            rand_x = random.randint(min_x, max_x)
+            rand_y = random.randint(min_y, max_y)
+            self._log(f"[{i+1}/{click_count}] Moving mouse to ({rand_x}, {rand_y}) and clicking")
+            self.mouse.click(rand_x, rand_y, humanize=True)
+            if i < click_count - 1:
+                sleep_time = random.uniform(0.5, 1.8)
+                self._log(f"Resting for {sleep_time:.2f} seconds before next click...")
+                time.sleep(sleep_time)
+        self._log("Random human clicks simulation completed.")
 
 
     def health_check(self) -> bool:
     def health_check(self) -> bool:
         if not self.is_healthy:
         if not self.is_healthy:

+ 125 - 39
utils/mouse.py

@@ -64,35 +64,35 @@ class MouseTimingConfig:
     frame_interval_variance: float = 0.004
     frame_interval_variance: float = 0.004
 
 
     curvature_min: float = 0.10
     curvature_min: float = 0.10
-    curvature_max: float = 0.30
+    curvature_max: float = 0.28
     curvature_asymmetry: float = 0.6
     curvature_asymmetry: float = 0.6
 
 
     short_distance_threshold: float = 50.0
     short_distance_threshold: float = 50.0
 
 
-    tremor_amplitude: float = 1.0
+    tremor_amplitude: float = 0.85
 
 
-    overshoot_probability: float = 0.70
+    overshoot_probability: float = 0.22
     overshoot_distance_min: float = 0.03
     overshoot_distance_min: float = 0.03
-    overshoot_distance_max: float = 0.12
-    overshoot_speed_threshold: float = 200.0
+    overshoot_distance_max: float = 0.10
+    overshoot_speed_threshold: float = 260.0
 
 
-    pre_click_pause_min: float = 0.05
-    pre_click_pause_max: float = 0.20
-    click_hold_min: float = 0.05
-    click_hold_max: float = 0.15
+    pre_click_pause_min: float = 0.04
+    pre_click_pause_max: float = 0.16
+    click_hold_min: float = 0.04
+    click_hold_max: float = 0.12
     double_click_interval_min: float = 0.05
     double_click_interval_min: float = 0.05
-    double_click_interval_max: float = 0.10
-    drag_start_pause_min: float = 0.08
-    drag_start_pause_max: float = 0.20
-    drag_end_pause_min: float = 0.05
-    drag_end_pause_max: float = 0.15
+    double_click_interval_max: float = 0.09
+    drag_start_pause_min: float = 0.06
+    drag_start_pause_max: float = 0.16
+    drag_end_pause_min: float = 0.04
+    drag_end_pause_max: float = 0.12
 
 
-    micro_pause_probability: float = 0.03
-    micro_pause_min: float = 0.015
-    micro_pause_max: float = 0.04
+    micro_pause_probability: float = 0.08
+    micro_pause_min: float = 0.010
+    micro_pause_max: float = 0.030
 
 
     min_duration: float = 0.08
     min_duration: float = 0.08
-    max_duration: float = 2.5
+    max_duration: float = 2.2
 
 
 
 
 class HumanMouse:
 class HumanMouse:
@@ -138,9 +138,10 @@ class HumanMouse:
         """
         """
         self._page = page
         self._page = page
         self._timing = timing or MouseTimingConfig()
         self._timing = timing or MouseTimingConfig()
-        self._position: Tuple[float, float] = (0.0, 0.0)
+        self._position: Tuple[float, float] = self._read_initial_position()
         self._debug = debug
         self._debug = debug
         self._debug_initialized = False
         self._debug_initialized = False
+        self._session_profile = self._build_session_profile()
 
 
     @property
     @property
     def timing(self) -> MouseTimingConfig:
     def timing(self) -> MouseTimingConfig:
@@ -254,16 +255,17 @@ class HumanMouse:
             return
             return
 
 
         config = self._timing
         config = self._timing
-        
+
         if custom_duration is not None:
         if custom_duration is not None:
             duration = custom_duration
             duration = custom_duration
         else:
         else:
             duration = fitts_duration(distance, 20.0, config.fitts_a, config.fitts_b)
             duration = fitts_duration(distance, 20.0, config.fitts_a, config.fitts_b)
             duration = max(config.min_duration, min(duration, config.max_duration))
             duration = max(config.min_duration, min(duration, config.max_duration))
+            duration *= self._session_profile["speed_scale"]
 
 
         should_overshoot = (
         should_overshoot = (
             distance > config.overshoot_speed_threshold
             distance > config.overshoot_speed_threshold
-            and random.random() < config.overshoot_probability
+            and random.random() < config.overshoot_probability * self._session_profile["overshoot_bias"]
         )
         )
 
 
         if should_overshoot:
         if should_overshoot:
@@ -272,7 +274,7 @@ class HumanMouse:
             cp1, cp2 = self._get_control_points(start, target)
             cp1, cp2 = self._get_control_points(start, target)
             self._perform_movement_loop(start, target, duration, cp1, cp2)
             self._perform_movement_loop(start, target, duration, cp1, cp2)
 
 
-        self._dispatch_move(target_x, target_y)
+        self._perform_final_correction(target_x, target_y)
 
 
     def _move_with_overshoot(
     def _move_with_overshoot(
         self,
         self,
@@ -308,6 +310,7 @@ class HumanMouse:
         config = self._timing
         config = self._timing
         start_time = time.perf_counter()
         start_time = time.perf_counter()
         prev = (start[0], start[1], start_time)
         prev = (start[0], start[1], start_time)
+        segment_pause_used = False
 
 
         while True:
         while True:
             now = time.perf_counter()
             now = time.perf_counter()
@@ -316,8 +319,9 @@ class HumanMouse:
             if elapsed >= duration:
             if elapsed >= duration:
                 break
                 break
 
 
-            t = minimum_jerk(elapsed / duration)
-            x, y = bezier_2d(t, start, cp1, cp2, end)
+            progress = elapsed / duration
+            eased = minimum_jerk(progress)
+            x, y = bezier_2d(eased, start, cp1, cp2, end)
 
 
             sigma = self._compute_tremor_sigma(x, y, now, prev, config)
             sigma = self._compute_tremor_sigma(x, y, now, prev, config)
             x += random.gauss(0, sigma)
             x += random.gauss(0, sigma)
@@ -326,15 +330,14 @@ class HumanMouse:
             self._dispatch_move(x, y)
             self._dispatch_move(x, y)
             prev = (x, y, now)
             prev = (x, y, now)
 
 
-            frame_delay = config.frame_interval + random.uniform(
-                -config.frame_interval_variance, config.frame_interval_variance
-            )
+            frame_delay = self._sample_frame_delay()
             time.sleep(max(0.001, frame_delay))
             time.sleep(max(0.001, frame_delay))
 
 
-            if random.random() < config.micro_pause_probability:
-                pause = random.uniform(config.micro_pause_min, config.micro_pause_max)
+            if (not segment_pause_used) and random.random() < config.micro_pause_probability:
+                pause = self._sample_micro_pause()
                 time.sleep(pause)
                 time.sleep(pause)
-                start_time += pause  # 补偿停顿时间
+                start_time += pause
+                segment_pause_used = True
 
 
     @staticmethod
     @staticmethod
     def _compute_tremor_sigma(
     def _compute_tremor_sigma(
@@ -361,27 +364,23 @@ class HumanMouse:
         click_count: int,
         click_count: int,
     ) -> None:
     ) -> None:
         """拟人化点击"""
         """拟人化点击"""
-        config = self._timing
-
         self._move_humanized(x, y)
         self._move_humanized(x, y)
+        self._micro_adjust_towards(x, y)
 
 
-        pre_pause = random.uniform(config.pre_click_pause_min, config.pre_click_pause_max)
+        pre_pause = self._sample_pre_click_pause()
         time.sleep(pre_pause)
         time.sleep(pre_pause)
 
 
         for i in range(click_count):
         for i in range(click_count):
             current_count = i + 1
             current_count = i + 1
             self._dispatch_button(MouseEventType.MOUSE_PRESSED, button, current_count)
             self._dispatch_button(MouseEventType.MOUSE_PRESSED, button, current_count)
 
 
-            hold = random.uniform(config.click_hold_min, config.click_hold_max)
+            hold = self._sample_click_hold()
             time.sleep(hold)
             time.sleep(hold)
 
 
             self._dispatch_button(MouseEventType.MOUSE_RELEASED, button, current_count)
             self._dispatch_button(MouseEventType.MOUSE_RELEASED, button, current_count)
 
 
             if current_count < click_count:
             if current_count < click_count:
-                interval = random.uniform(
-                    config.double_click_interval_min,
-                    config.double_click_interval_max,
-                )
+                interval = self._sample_double_click_interval()
                 time.sleep(interval)
                 time.sleep(interval)
 
 
     def _drag_humanized(
     def _drag_humanized(
@@ -442,6 +441,52 @@ class HumanMouse:
         if self._debug:
         if self._debug:
             self._debug_draw_dot(x, y, radius=2, color='rgba(0,150,255,0.6)')
             self._debug_draw_dot(x, y, radius=2, color='rgba(0,150,255,0.6)')
 
 
+    def _sample_frame_delay(self) -> float:
+        config = self._timing
+        base = config.frame_interval * self._session_profile["tempo_scale"]
+        spread = config.frame_interval_variance * self._session_profile["tempo_jitter"]
+        return random.gauss(base, max(0.001, spread))
+
+    def _sample_pre_click_pause(self) -> float:
+        config = self._timing
+        return max(
+            0.0,
+            random.gauss(
+                (config.pre_click_pause_min + config.pre_click_pause_max) / 2.0,
+                (config.pre_click_pause_max - config.pre_click_pause_min) / 6.0,
+            ),
+        )
+
+    def _sample_click_hold(self) -> float:
+        config = self._timing
+        return max(
+            0.0,
+            random.gauss(
+                (config.click_hold_min + config.click_hold_max) / 2.0,
+                (config.click_hold_max - config.click_hold_min) / 6.0,
+            ),
+        )
+
+    def _sample_double_click_interval(self) -> float:
+        config = self._timing
+        return max(
+            0.0,
+            random.gauss(
+                (config.double_click_interval_min + config.double_click_interval_max) / 2.0,
+                (config.double_click_interval_max - config.double_click_interval_min) / 6.0,
+            ),
+        )
+
+    def _sample_micro_pause(self) -> float:
+        config = self._timing
+        return max(
+            0.0,
+            random.gauss(
+                (config.micro_pause_min + config.micro_pause_max) / 2.0,
+                (config.micro_pause_max - config.micro_pause_min) / 6.0,
+            ),
+        )
+
     def _dispatch_button(
     def _dispatch_button(
         self,
         self,
         event_type: MouseEventType,
         event_type: MouseEventType,
@@ -470,4 +515,45 @@ class HumanMouse:
             self._debug_initialized = True
             self._debug_initialized = True
 
 
         script = self._DEBUG_DOT_JS % (int(round(x)), int(round(y)), radius, color)
         script = self._DEBUG_DOT_JS % (int(round(x)), int(round(y)), radius, color)
-        self._page.run_js(script)
+        self._page.run_js(script)
+
+    def _read_initial_position(self) -> Tuple[float, float]:
+        try:
+            data = self._page.run_js("return { x: window.screenX || 0, y: window.screenY || 0 };")
+            if isinstance(data, dict):
+                return (float(data.get("x", 0.0)), float(data.get("y", 0.0)))
+        except Exception:
+            pass
+        return (0.0, 0.0)
+
+    def _build_session_profile(self) -> dict:
+        return {
+            "speed_scale": random.uniform(0.90, 1.15),
+            "tempo_scale": random.uniform(0.92, 1.10),
+            "tempo_jitter": random.uniform(0.85, 1.25),
+            "overshoot_bias": random.uniform(0.65, 1.15),
+        }
+
+    def _perform_final_correction(self, target_x: float, target_y: float) -> None:
+        current_x, current_y = self._position
+        distance = math.hypot(target_x - current_x, target_y - current_y)
+        if distance <= 1.5:
+            self._dispatch_move(target_x, target_y)
+            return
+
+        correction_end = (target_x, target_y)
+        cp1, cp2 = self._get_control_points((current_x, current_y), correction_end)
+        duration = min(self._timing.max_duration, max(self._timing.min_duration, 0.12 + distance / 900.0))
+        self._perform_movement_loop((current_x, current_y), correction_end, duration, cp1, cp2)
+        self._dispatch_move(target_x, target_y)
+
+    def _micro_adjust_towards(self, x: float, y: float) -> None:
+        current_x, current_y = self._position
+        distance = math.hypot(x - current_x, y - current_y)
+        if distance < 5.0:
+            return
+        offset_x = random.uniform(-1.0, 1.0)
+        offset_y = random.uniform(-1.0, 1.0)
+        self._dispatch_move(x + offset_x, y + offset_y)
+        time.sleep(random.uniform(0.006, 0.018))
+        self._dispatch_move(x, y)