From 82ea40d3dc0859597fcaf10550b75b6f4490ab63 Mon Sep 17 00:00:00 2001 From: KenanZhu <3471685733@qq.com> Date: Sat, 8 Nov 2025 12:53:24 +0800 Subject: [PATCH] refactor(LibChecker): fix(AutoLib): extract reservation decode logic into separate function : adjust default browser size to prevent page scale issues Extract the reservation decode logic into a separate function within LibChecker to improve code structure and enable more structured return values for decision-making. Testing of the refactored LibChecker revealed that page scaling could cause unexpected behavior. Change the default browser size from 1280x720 to 1920x1080 to resolve this. --- AutoLib.py | 3 +- LibChecker.py | 211 ++++++++++++++++++++++++++++++++------------------ 2 files changed, 136 insertions(+), 78 deletions(-) diff --git a/AutoLib.py b/AutoLib.py index 721a97e..7d7ba08 100644 --- a/AutoLib.py +++ b/AutoLib.py @@ -52,7 +52,8 @@ class AutoLib(MsgBase): edge_options.add_argument("--no-sandbox") edge_options.add_argument("--disable-dev-shm-usage") - edge_options.add_argument("--window-size=1280,720") + # must be 1920x1080, otherwise the page will cause some elements not accessible + edge_options.add_argument("--window-size=1920,1080") edge_options.add_argument("--remote-allow-origins=*") # omit ssl errors and verbose log level diff --git a/LibChecker.py b/LibChecker.py index 8349530..5b3e097 100644 --- a/LibChecker.py +++ b/LibChecker.py @@ -57,6 +57,83 @@ class LibChecker(LibOperator): return True + def __decodeReserveInfo( + self, + info_elements + ) -> str: + + location = "" + status = "" + for info in info_elements: + if "已预约" in info.text: + status = "已预约" + elif "使用中" in info.text: + status = "使用中" + elif "已完成" in info.text: + status = "已完成" + elif "已结束使用" in info.text: + status = "已结束使用" + elif "已取消" in info.text: + status = "已取消" + elif "失约" in info.text: + status = "失约" + elif "图书馆" in info.text: + location = info.text.strip() + return { + "location": location, + "status": status, + } + + + def __decodeReserveRecord( + self, + reservation + ) -> dict: + + try: + time_element = reservation.find_element( + By.CSS_SELECTOR, "dt" + ) + info_elements = reservation.find_elements( + By.CSS_SELECTOR, "a" + ) + except: + return None + # process time element to get the date string + time_str = time_element.text.strip() + today = datetime.now().date() + if "明天" in time_str: + target_date = today + timedelta(days=1) + date_str = target_date.strftime("%Y-%m-%d") + elif "今天" in time_str: + target_date = today + date_str = target_date.strftime("%Y-%m-%d") + elif "昨天" in time_str: + target_date = today - timedelta(days=1) + date_str = target_date.strftime("%Y-%m-%d") + else: + date_match = re.search(r"(\d{4}-\d{1,2}-\d{1,2})", time_str) + if date_match: + date_str = date_match.group(1) + else: + date_str = "" + time_match = re.search(r"(\d{1,2}:\d{2}) -- (\d{1,2}:\d{2})", time_str) + if time_match: + begin_time = time_match.group(1) + end_time = time_match.group(2) + else: + time_str = "" + info = self.__decodeReserveInfo(info_elements) + return { + "date": date_str, + "time": { + "begin": begin_time, + "end": end_time, + }, + "info": info + } + + def __getReserveRecord( self, wanted_date: str, @@ -66,75 +143,58 @@ class LibChecker(LibOperator): if wanted_date is None: self._showTrace("日期未指定, 无法检查当前预约状态") return None - self._showTrace(f"正在检查用户在日期 {wanted_date} 是否有预约状态为 {wanted_status} 的预约记录......") + self._showTrace(f"正在检查用户在 {wanted_date} 是否有预约状态为 {wanted_status} 的预约记录......") date_obj = datetime.strptime(wanted_date, "%Y-%m-%d").date() checked_count = 0 - max_check_times = 3 # we only check (3*4=)12 reservations + max_check_times = 6 # we only check (4*(6-1)=)20 reservations, the last time cant be checked if not self.__navigateToReserveRecordPage(): return None for _ in range(max_check_times): try: # check if there's any reservation on the date + WebDriverWait(self.__driver, 2).until( + EC.presence_of_element_located((By.CSS_SELECTOR, ".myReserveList > dl")) + ) reservations = self.__driver.find_elements( - By.CSS_SELECTOR, ".myReserveList dl" + By.CSS_SELECTOR, ".myReserveList > dl:not(#moreBlock)" ) except: self._showTrace("加载预约记录失败 !") return None - for i in range(checked_count, len(reservations) - 1): # the last one is load button + for i in range(checked_count, len(reservations)): # the last one is load button reservation = reservations[i] - try: - time_element = reservation.find_element( - By.CSS_SELECTOR, "dt" - ) - info_elements = reservation.find_elements( - By.CSS_SELECTOR, "a" - ) - except: - self._showTrace(f"解析第 {i + 1} 条预约记录时发生未知错误 !") + record = self.__decodeReserveRecord(reservation) + print(record) + if record is None: continue - is_wanted = any(wanted_status in status.text for status in info_elements) - # process time element to get the date string - time_str = time_element.text.strip() - today = datetime.now().date() - if "明天" in time_str: - target_date = today + timedelta(days=1) - date_str = target_date.strftime("%Y-%m-%d") - elif "今天" in time_str: - target_date = today - date_str = target_date.strftime("%Y-%m-%d") - elif "昨天" in time_str: - target_date = today - timedelta(days=1) - date_str = target_date.strftime("%Y-%m-%d") - else: - date_match = re.search(r'(\d{4}-\d{1,2}-\d{1,2})', time_str) - if date_match: - date_str = date_match.group(1) - else: - self._showTrace(f"无法解析第 {i + 1} 条预约记录的日期 ! 该记录的时间为 {time_str}") - continue + record_date = record["date"] + record_time = record["time"] + status = record["info"]["status"] + location = record["info"]["location"] + if record_date == "" or record_time == {"begin": "", "end": ""}: + continue + is_wanted = (status == wanted_status) # reservation is later than the given date, check the next one - if datetime.strptime(date_str, "%Y-%m-%d").date() > date_obj: + if datetime.strptime(record_date, "%Y-%m-%d").date() > date_obj: continue # reservation is earlier than the given date, can reserve - if datetime.strptime(date_str, "%Y-%m-%d").date() < date_obj: + if datetime.strptime(record_date, "%Y-%m-%d").date() < date_obj: return None # query the wanted status if is_wanted: - self._showTrace(f"寻找到第 {i + 1} 条预约记录, 状态为 {wanted_status}") - time_match = re.search(r"(\d{1,2}:\d{2}) -- (\d{1,2}:\d{2})", time_str) - if time_match is None: - self._showTrace(f"无法解析第 {i + 1} 条预约记录的时间 ! 该记录的时间为 {time_str}") - continue + self._showTrace( + f"寻找到用户第 {i + 1} 条状态为 {wanted_status} 的预约记录, " + f"详细信息: {record_date} {record_time['begin']} - {record_time['end']} {location}" + ) return { "index": i, - "date": date_str, - "time_str": time_match.group(0), + "date": record_date, + "time": record_time, "status": wanted_status } - checked_count = len(reservations) - 1 + checked_count = len(reservations) # load new reservations if still not sure try: more_btn = self.__driver.find_element(By.ID, "moreBtn") @@ -142,7 +202,7 @@ class LibChecker(LibOperator): self.__driver.execute_script("arguments[0].scrollIntoView(true);", more_btn) self.__driver.execute_script("arguments[0].click();", more_btn) else: - self._showTrace("该用户无法加载更多预约记录") + self._showTrace("用户无法加载更多预约记录") break except: self._showTrace("加载更多预约记录失败 !") @@ -159,10 +219,11 @@ class LibChecker(LibOperator): # then can reserve if self.__getReserveRecord(date, "已预约") is None: if self.__getReserveRecord(date, "使用中") is None: - self._showTrace(f"用户在日期 {date} 可以预约") + self._showTrace(f"用户在 {date} 可以预约") return True - self._showTrace(f"用户在日期 {date} 有使用中的预约, 无法预约") - self._showTrace(f"用户在日期 {date} 已存在有效预约, 无法预约") + self._showTrace(f"用户在 {date} 有使用中的预约, 无法预约") + return False + self._showTrace(f"用户在 {date} 已存在有效预约, 无法预约") return False @@ -174,34 +235,30 @@ class LibChecker(LibOperator): # have a reserved record in the given date record = self.__getReserveRecord(date, "已预约") if record is not None: - time_match = re.search(r"(\d{1,2}:\d{2})", record["time_str"]) - if time_match: - begin_time = time_match.group(0) - begin_time = datetime.strptime(f"{date} {begin_time}", "%Y-%m-%d %H:%M") - time_diff = datetime.now() - begin_time - time_diff_seconds = time_diff.total_seconds() - # before 30 minutes, cant checkin - if time_diff_seconds < -30*60: - self._showTrace( - f"用户在日期 {date} 的预约开始时间为 {begin_time}, " - f"距离当前时间还有 {abs(time_diff_seconds)/60:.2f} 分钟, 无法签到" - ) - return False - # before in 30 minutes, can checkin - elif -30*60 <= time_diff_seconds < 0: - self._showTrace( - f"用户在日期 {date} 的预约开始时间为 {begin_time}, " - f"距离当前时间还有 {abs(time_diff_seconds)/60:.2f} 分钟, 可以签到" - ) - return True - # past less than 30 minutes, can checkin - elif 0 <= time_diff_seconds < 30*60: - self._showTrace( - f"用户在日期 {date} 的预约开始时间为 {begin_time}, " - f"当前时间已经 {abs(time_diff_seconds)/60:.2f} 分钟, 可以签到" - ) - return True - else: - self._showTrace(f"用户在日期 {date} 的预约时间格式错误, 无法签到") - self._showTrace(f"用户在日期 {date} 有没有有效预约记录, 无法签到") + begin_time = record["time"]["begin"] + begin_time = datetime.strptime(f"{date} {begin_time}", "%Y-%m-%d %H:%M") + time_diff = datetime.now() - begin_time + time_diff_seconds = time_diff.total_seconds() + # before 30 minutes, cant checkin + if time_diff_seconds < -30*60: + self._showTrace( + f"用户在 {date} 的预约开始时间为 {begin_time}, " + f"距离当前时间还有 {abs(time_diff_seconds)/60:.2f} 分钟, 无法签到" + ) + return False + # before in 30 minutes, can checkin + elif -30*60 <= time_diff_seconds < 0: + self._showTrace( + f"用户在 {date} 的预约开始时间为 {begin_time}, " + f"距离当前时间还有 {abs(time_diff_seconds)/60:.2f} 分钟, 可以签到" + ) + return True + # past less than 30 minutes, can checkin + elif 0 <= time_diff_seconds < 30*60: + self._showTrace( + f"用户在 {date} 的预约开始时间为 {begin_time}, " + f"当前时间已经 {abs(time_diff_seconds)/60:.2f} 分钟, 可以签到" + ) + return True + self._showTrace(f"用户在 {date} 有没有有效预约记录, 无法签到") return False