""" PyAutoGUI 公共封装:统一 PAUSE / FAILSAFE、移动点击、键入与随机停顿。 其它脚本请使用「from workplace.pyautogui import …」,勿把 workplace 目录单独插到 sys.path 最前再 `import pyautogui`,以免与 pip 包名冲突。 依赖:pip install pyautogui """ from __future__ import annotations import random import time from typing import Any import pyautogui as _pa # 可调默认节奏(秒) DEFAULT_MOVE_DURATION = 0.2 DEFAULT_CLICK_INTERVAL = 0.05 DEFAULT_TYPE_INTERVAL = 0.03 def configure(*, pause: float = 0.05, failsafe: bool = True) -> None: """每步操作之间的全局暂停;FAILSAFE:鼠标移到屏幕左上角可抛异常中断。""" _pa.PAUSE = pause _pa.FAILSAFE = failsafe def init_singleton(*, pause: float = 0.05, failsafe: bool = True) -> None: """ 应用入口显式初始化(与 ``main.start`` 开头调用一次);多次调用安全,会再次 ``configure``。 导入本模块时已 ``configure()`` 一次;此处供流程上「单例就绪」语义。 """ configure(pause=pause, failsafe=failsafe) configure() def human_pause(min_s: float = 0.05, max_s: float = 0.22) -> None: """短随机等待,模拟人手间隔。""" time.sleep(random.uniform(min_s, max_s)) def sleep_human_pre_click_after_pointer_move() -> None: """移鼠落稳后、左键前:约 0.12–0.42s(瞄准/制动,常见数百毫秒量级)。""" time.sleep(random.uniform(0.12, 0.42)) def sleep_human_pointer_poll_step() -> None: """轮询指针是否到位,非主观停顿;略拉开间隔减轻忙等。""" time.sleep(random.uniform(0.018, 0.048)) def sleep_human_after_pointer_settled_before_typing() -> None: """指针已到目标、即将点击聚焦输入框前:约 0.10–0.42s。""" time.sleep(random.uniform(0.10, 0.42)) def sleep_human_chrome_debug_process_ready() -> None: """远程调试 Chrome 新进程就绪(非人手,仅拉开方差)。""" time.sleep(random.uniform(2.35, 3.12)) def sleep_human_screenshot_settled_before_template_match() -> None: """截屏后等界面静止再跑模板匹配:约 0.72–1.68s。""" time.sleep(random.uniform(0.72, 1.68)) def sleep_human_ui_scan_short() -> None: """扫一眼列表/等展开动效:约 0.55–1.45s。""" time.sleep(random.uniform(0.55, 1.45)) def sleep_human_ui_scan_after_small_cursor_nudge() -> None: """微移光标(如 move_rel)后接下一步:约 0.32–0.82s。""" time.sleep(random.uniform(0.32, 0.82)) def sleep_human_between_feed_filter_steps() -> None: """筛选流里步骤间略读界面:约 0.58–1.48s。""" time.sleep(random.uniform(0.58, 1.48)) def sleep_human_before_click_sort_or_tab_after_move() -> None: """已移到排序项/「图文」等目标、按下前:约 0.48–1.28s。""" time.sleep(random.uniform(0.48, 1.28)) def sleep_human_open_feed_card_before_title_click() -> None: """列表点开笔记前略读标题区:约 1.05–2.15s。""" time.sleep(random.uniform(1.05, 2.15)) def sleep_human_after_feed_card_opens_detail() -> None: """进入详情后等布局稳定:约 0.70–1.58s。""" time.sleep(random.uniform(0.70, 1.58)) def sleep_human_top_bar_filter_after_detail_before_click() -> None: """从详情回到顶栏点「筛选」:约 0.26–0.64s。""" time.sleep(random.uniform(0.26, 0.64)) def sleep_human_extra_after_dom_click_poll(*, base_sec: float) -> None: """点击后等 DOM/输入值更新:在 ``base_sec`` 上再加一段随机余量。""" b = float(base_sec) time.sleep(b + random.uniform(0, min(0.14, max(0.04, b * 0.32)))) def screen_size() -> tuple[int, int]: """当前屏幕逻辑分辨率 (width, height)。""" w, h = _pa.size() return int(w), int(h) def move_to(x: int, y: int, *, duration: float = DEFAULT_MOVE_DURATION) -> None: _pa.moveTo(int(x), int(y), duration=duration) def move_rel(dx: int, dy: int, *, duration: float = DEFAULT_MOVE_DURATION) -> None: """相对当前光标移动(屏幕像素);与视口内向量配合时通常假设 CSS 像素与屏幕位移一致。""" _pa.moveRel(int(dx), int(dy), duration=duration) def click_at( x: int, y: int, *, duration: float = DEFAULT_MOVE_DURATION, clicks: int = 1, interval: float = DEFAULT_CLICK_INTERVAL, button: str = "left", ) -> None: _pa.click( int(x), int(y), clicks=clicks, interval=interval, duration=duration, button=button, ) def click_here(*, clicks: int = 1, interval: float = DEFAULT_CLICK_INTERVAL) -> None: """在当前鼠标位置点击。""" _pa.click(clicks=clicks, interval=interval) def type_text(text: str, *, interval: float = DEFAULT_TYPE_INTERVAL) -> None: """逐字符键入(英文/数字为主;中文需系统输入法已就绪)。""" _pa.write(text, interval=interval) def press_key(key: str, *, presses: int = 1, interval: float = 0.05) -> None: _pa.press(key, presses=presses, interval=interval) def hotkey(*keys: str, interval: float = 0.05) -> None: _pa.hotkey(*keys, interval=interval) def scroll_at( x: int, y: int, clicks: int, *, duration: float = DEFAULT_MOVE_DURATION, ) -> None: """先移到坐标再滚轮;clicks 正数向上、负数向下(与 PyAutoGUI 一致)。""" move_to(x, y, duration=duration) _pa.scroll(int(clicks)) # 需要直接调官方 API 时用(如 locateOnScreen) raw: Any = _pa __all__ = [ "configure", "init_singleton", "human_pause", "sleep_human_pre_click_after_pointer_move", "sleep_human_pointer_poll_step", "sleep_human_after_pointer_settled_before_typing", "sleep_human_chrome_debug_process_ready", "sleep_human_screenshot_settled_before_template_match", "sleep_human_ui_scan_short", "sleep_human_ui_scan_after_small_cursor_nudge", "sleep_human_between_feed_filter_steps", "sleep_human_before_click_sort_or_tab_after_move", "sleep_human_open_feed_card_before_title_click", "sleep_human_after_feed_card_opens_detail", "sleep_human_top_bar_filter_after_detail_before_click", "sleep_human_extra_after_dom_click_poll", "screen_size", "move_to", "move_rel", "click_at", "click_here", "type_text", "press_key", "hotkey", "scroll_at", "raw", ]