find_search_input.py 3.0 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091
  1. #!/usr/bin/env python3
  2. """
  3. 用 ``workplace/ocr-pos.py``(RapidOCR)在**当前屏幕截图**中查找固定文案,
  4. 返回文字框中心点的**屏幕像素坐标** ``(x, y)``;入口为 ``start``。
  5. 保留 ``selector_search_input`` / ``SEARCH_INPUT_SELECTORS`` 供 ``input-word-by-word.py`` 等旧代码导入。
  6. """
  7. from __future__ import annotations
  8. import importlib.util
  9. import sys
  10. from pathlib import Path
  11. from typing import TYPE_CHECKING
  12. if TYPE_CHECKING:
  13. from playwright.sync_api import Page
  14. target_text = "搜索小红书"
  15. _REPO = Path(__file__).resolve().parent.parent.parent
  16. if str(_REPO) not in sys.path:
  17. sys.path.insert(0, str(_REPO))
  18. from workplace.screenshot import PillowImageGrabFullScreenScreenshotCaptureSaver # noqa: E402
  19. SEARCH_INPUT_SELECTORS: tuple[str, ...] = (
  20. "#search-input",
  21. "input#search-input",
  22. "textarea#search-input",
  23. )
  24. selector_search_input = SEARCH_INPUT_SELECTORS[0]
  25. class SearchInputFlowResult:
  26. """不用 ``@dataclass``:经 ``exec_module`` 动态加载时,与 ``from __future__ import annotations`` 组合可能触发 CPython dataclasses 内部错误。"""
  27. __slots__ = ("ok", "message", "center_xy")
  28. def __init__(
  29. self,
  30. ok: bool,
  31. message: str = "",
  32. center_xy: tuple[int, int] | None = None,
  33. ) -> None:
  34. self.ok = ok
  35. self.message = message
  36. self.center_xy = center_xy
  37. def _load_ocr_pos():
  38. path = Path(__file__).resolve().parent.parent / "ocr-pos.py"
  39. spec = importlib.util.spec_from_file_location("workplace_ocr_pos_script", path)
  40. if spec is None or spec.loader is None:
  41. raise ImportError(f"Cannot load {path}")
  42. mod = importlib.util.module_from_spec(spec)
  43. spec.loader.exec_module(mod)
  44. return mod
  45. def start(
  46. page: Page,
  47. keyword: str = "",
  48. *,
  49. preset_center_xy: tuple[int, int] | None = None,
  50. ) -> SearchInputFlowResult:
  51. """
  52. 截取整屏(``capture_full_screen_and_store_in_memory`` 返回 BGR 图,并同步写入 ``workplace.screenshot`` 模块变量),
  53. OCR 匹配 ``target_text``(与 ``keyword`` 无关),返回中心点屏幕坐标。
  54. 若传入 ``preset_center_xy`` 则跳过截图与 OCR,直接返回该坐标。
  55. ``page`` 仅保留签名兼容。
  56. """
  57. _ = page, keyword
  58. if preset_center_xy is not None:
  59. x, y = int(preset_center_xy[0]), int(preset_center_xy[1])
  60. return SearchInputFlowResult(ok=True, message="", center_xy=(x, y))
  61. ocr_mod = _load_ocr_pos()
  62. saver = PillowImageGrabFullScreenScreenshotCaptureSaver()
  63. full_screen_screenshot_bgr_numpy = saver.capture_full_screen_and_store_in_memory()
  64. pt = ocr_mod.ocr_find_text_center(
  65. full_screen_screenshot_bgr_numpy,
  66. target_text,
  67. )
  68. if pt is None:
  69. msg = f"OCR 未在全屏截图中找到「{target_text}」。"
  70. print(msg, file=sys.stderr)
  71. return SearchInputFlowResult(ok=False, message=msg, center_xy=None)
  72. return SearchInputFlowResult(ok=True, message="", center_xy=pt)