| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133 |
- import time
- import random
- import math
- def get_cubic_bezier_point(t, p0, p1, p2, p3):
- x = (1-t)**3 * p0[0] + 3*(1-t)**2 * t * p1[0] + 3*(1-t) * t**2 * p2[0] + t**3 * p3[0]
- y = (1-t)**3 * p0[1] + 3*(1-t)**2 * t * p1[1] + 3*(1-t) * t**2 * p2[1] + t**3 * p3[1]
- return (x, y)
- def ease_out_quad(x):
- return 1 - (1 - x) * (1 - x)
- def generate_human_path(start_x, start_y, end_x, end_y, steps=30):
- path = []
- dist = math.hypot(end_x - start_x, end_y - start_y)
- offset = dist * 0.2
-
- p0 = (start_x, start_y)
- p3 = (end_x, end_y)
-
- p1 = (
- start_x + (end_x - start_x) * 0.3 + random.uniform(-offset, offset),
- start_y + (end_y - start_y) * 0.3 + random.uniform(-offset, offset)
- )
- p2 = (
- start_x + (end_x - start_x) * 0.7 + random.uniform(-offset, offset),
- start_y + (end_y - start_y) * 0.7 + random.uniform(-offset, offset)
- )
- for i in range(steps + 1):
- t = i / steps
- eased_t = ease_out_quad(t)
- point = get_cubic_bezier_point(eased_t, p0, p1, p2, p3)
- jitter = 1.5
- final_x = point[0] + random.uniform(-jitter, jitter)
- final_y = point[1] + random.uniform(-jitter, jitter)
- if i == steps:
- final_x, final_y = end_x, end_y
- path.append((final_x, final_y))
- return path
- class HumanMouse:
- def __init__(self, page):
- self.page = page
- self.curr_x = random.randint(100, 500)
- self.curr_y = random.randint(100, 500)
-
- self.page.run_cdp('Input.dispatchMouseEvent', **{
- 'type': 'mouseMoved',
- 'x': self.curr_x,
- 'y': self.curr_y
- })
- def _get_center(self, ele):
- """兼容性获取中心点"""
- rect = ele.rect
- try:
- tl_x, tl_y = rect.location
- width, height = rect.size
- except AttributeError:
- tl_x, tl_y, width, height = rect
- return tl_x + (width / 2), tl_y + (height / 2)
- def move_to(self, ele, duration=0.5):
- center_x, center_y = self._get_center(ele)
-
- # 目标稍微带点随机偏移
- target_x = center_x + random.uniform(-3, 3)
- target_y = center_y + random.uniform(-3, 3)
-
- if self.curr_x == 0 and self.curr_y == 0:
- self.curr_x = target_x - random.randint(300, 500)
- self.curr_y = target_y - random.randint(300, 500)
- self.page.run_cdp('Input.dispatchMouseEvent', **{
- 'type': 'mouseMoved',
- 'x': self.curr_x,
- 'y': self.curr_y
- })
- steps = int(duration * 60)
- if steps < 10: steps = 10
-
- points = generate_human_path(self.curr_x, self.curr_y, target_x, target_y, steps)
-
- for x, y in points:
- self.page.run_cdp('Input.dispatchMouseEvent', **{
- 'type': 'mouseMoved',
- 'x': x,
- 'y': y
- })
- self.curr_x = x
- self.curr_y = y
- time.sleep(duration / steps * random.uniform(0.8, 1.2))
- def scroll_to_visible(self, ele):
- viewport_height = self.page.run_js("return window.innerHeight")
- while True:
- # 使用 arguments[0] 修复 run_js 参数问题
- rect = self.page.run_js("""
- var rect = arguments[0].getBoundingClientRect();
- return {top: rect.top, bottom: rect.bottom, height: rect.height};
- """, ele)
-
- element_top = rect['top']
- element_bottom = rect['bottom']
-
- scroll_needed = False
- delta_y = 0
-
- # 增加一些缓冲区,不要滚得太极限
- if element_top > viewport_height * 0.7:
- scroll_needed = True
- delta_y = random.randint(100, 250)
- elif element_bottom < viewport_height * 0.3:
- scroll_needed = True
- delta_y = -random.randint(100, 250)
-
- if not scroll_needed:
- break
-
- self._dispatch_scroll(delta_y)
- time.sleep(random.uniform(0.1, 0.2))
- def _dispatch_scroll(self, delta_y):
- self.page.run_cdp('Input.dispatchMouseEvent', **{
- 'type': 'mouseWheel',
- 'x': self.curr_x,
- 'y': self.curr_y,
- 'deltaX': 0,
- 'deltaY': delta_y,
- 'modifiers': 0,
- 'pointerType': 'mouse'
- })
|