mirror of
https://github.com/KenanZhu/AutoLibrary.git
synced 2026-06-18 07:23:03 +08:00
refactor(pages): 引入 Page Object 模式重构全部页面模块,变量统一为 snake_case
将原始 Selenium 操作脚本重构为三层 Page Object 架构: - Page Objects(LoginPage/ReserveView/RecordsView/MainShell) - Component Objects(Overlay 基类 + SeatMapOverlay/ReserveResultDialog 等对话框) - Flow 状态机(ReserveFlow/CheckinFlow/RenewFlow) - Services(CaptchaHandler/ReserveValidator/RecordChecker) 变量命名统一为 snake_case,方法名保持 camelCase,类名保持 PascalCase。 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,101 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Copyright (c) 2026 KenanZhu.
|
||||
All rights reserved.
|
||||
|
||||
This software is provided "as is", without any warranty of any kind.
|
||||
You may use, modify, and distribute this file under the terms of the MIT License.
|
||||
See the LICENSE file for details.
|
||||
"""
|
||||
import base64
|
||||
import queue
|
||||
|
||||
import ddddocr
|
||||
from selenium.common.exceptions import (
|
||||
NoSuchElementException,
|
||||
TimeoutException,
|
||||
)
|
||||
|
||||
from base.MsgBase import MsgBase
|
||||
from pages.LoginPage import LoginPage
|
||||
|
||||
|
||||
class CaptchaHandler(MsgBase):
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
input_queue: queue.Queue,
|
||||
output_queue: queue.Queue,
|
||||
login_page: LoginPage,
|
||||
) -> None:
|
||||
|
||||
super().__init__(input_queue, output_queue)
|
||||
self._login_page = login_page
|
||||
self._ocr = ddddocr.DdddOcr()
|
||||
|
||||
def solveCaptcha(
|
||||
self,
|
||||
auto_captcha: bool = True,
|
||||
) -> str:
|
||||
|
||||
max_attempts = 3
|
||||
for _ in range(max_attempts):
|
||||
if auto_captcha:
|
||||
captcha_text = self._autoRecognize()
|
||||
else:
|
||||
self._showTrace("用户未配置自动识别验证码, 请手动输入验证码 !", 20, no_log=True)
|
||||
captcha_text = self._manualRecognize()
|
||||
if captcha_text:
|
||||
return captcha_text
|
||||
else:
|
||||
if not self._login_page.refreshCaptcha():
|
||||
return ""
|
||||
self._showTrace(
|
||||
f"验证码识别失败 {max_attempts} 次, 达到最大尝试次数 !",
|
||||
self.TraceLevel.WARNING,
|
||||
)
|
||||
return ""
|
||||
|
||||
def _autoRecognize(
|
||||
self,
|
||||
) -> str:
|
||||
|
||||
try:
|
||||
img_src = self._login_page.getCaptchaImageSrc()
|
||||
base64_str = img_src.split(',', 1)[1]
|
||||
captcha_img = base64.b64decode(base64_str)
|
||||
captcha_text = self._ocr.classification(captcha_img)
|
||||
captcha_text = ''.join(filter(str.isalnum, captcha_text)).lower()
|
||||
self._showTrace(f"识别到验证码为 : '{captcha_text}'", 20, no_log=True)
|
||||
if len(captcha_text) != 4:
|
||||
self._showLog("识别到的验证码长度不等于 4 个字符 !", self.TraceLevel.WARNING)
|
||||
raise Exception("识别到的验证码长度不等于 4 个字符 !")
|
||||
return captcha_text
|
||||
except (NoSuchElementException, TimeoutException) as e:
|
||||
self._showTrace(f"验证码识别失败 ! : {e}", self.TraceLevel.ERROR)
|
||||
return ""
|
||||
except (ValueError, OSError) as e:
|
||||
self._showTrace(f"验证码识别失败 ! : {e}", self.TraceLevel.ERROR)
|
||||
return ""
|
||||
except Exception as e:
|
||||
self._showTrace(f"验证码识别失败 ! : {e}", self.TraceLevel.ERROR)
|
||||
return ""
|
||||
|
||||
def _manualRecognize(
|
||||
self,
|
||||
) -> str:
|
||||
|
||||
try:
|
||||
self._showMsg("请输入验证码:")
|
||||
captcha_text = self._waitMsg(timeout=15)
|
||||
self._showTrace(f"输入的验证码为 : '{captcha_text}'", 20, no_log=True)
|
||||
if len(captcha_text) != 4:
|
||||
self._showLog("输入的验证码长度不等于 4 个字符 !", self.TraceLevel.WARNING)
|
||||
raise Exception("输入的验证码长度不等于 4 个字符 !")
|
||||
return captcha_text
|
||||
except ValueError as e:
|
||||
self._showTrace(f"输入验证码失败 ! : {e}", self.TraceLevel.ERROR)
|
||||
return ""
|
||||
except Exception as e:
|
||||
self._showTrace(f"输入验证码失败 ! : {e}", self.TraceLevel.ERROR)
|
||||
return ""
|
||||
Reference in New Issue
Block a user