# -*- coding: utf-8 -*- """Human-like interaction primitives for Playwright locators (no logging).""" from __future__ import annotations import random import time def pause(min_ms: int = 200, max_ms: int = 800) -> None: """随机停顿 min_ms ~ max_ms 毫秒。""" lo = min(min_ms, max_ms) / 1000.0 hi = max(min_ms, max_ms) / 1000.0 time.sleep(random.uniform(lo, hi)) def human_type( locator, text: str, *, per_char_ms_range: tuple[int, int] = (50, 200), pre_pause: bool = True, ) -> None: """逐字符输入(locator.type + delay);locator 为 Playwright Locator。""" locator.scroll_into_view_if_needed() if pre_pause: pause() locator.click() pause() lo, hi = per_char_ms_range delay_ms = random.uniform(float(lo), float(hi)) locator.type(text, delay=int(delay_ms)) def human_click(locator) -> None: """人类化点击:scroll_into_view → pause → click → pause""" locator.scroll_into_view_if_needed() pause() locator.click() pause() def human_select(locator, value_or_label: str) -> None: """人类化下拉选择:scroll_into_view → pause → click → pause → select_option""" locator.scroll_into_view_if_needed() pause() locator.click() pause() try: locator.select_option(value=value_or_label) except Exception: locator.select_option(label=value_or_label) def human_scroll_to(locator) -> None: """滚动到元素并稍作停顿。""" locator.scroll_into_view_if_needed() pause()