def update_fallback(config: CommonConfig): if not is_windows(): return try: # 到这里一般是无法访问github,这时候试试gitee的方案 latest_version = get_version_from_gitee() ui = UpdateInfo() ui.latest_version = latest_version ui.netdisk_link = config.netdisk_link ui.netdisk_passcode = "fzls" ui.update_message = "当前无法访问github,暂时无法获取更新内容,若欲知更新内容,请浏览gitee主页进行查看哦~\n\nhttps://gitee.com/fzls/djc_helper/blob/master/CHANGELOG.MD" try_manaual_update(ui) except Exception as err: logger.error( f"手动检查版本更新失败(这个跟自动更新没有任何关系),大概率是访问不了github和gitee导致的,可自行前往网盘查看是否有更新, 错误为{err}" + color("bold_green") + f"\n(无法理解上面这段话的话,就当没看见这段话,对正常功能没有任何影响)") # 如果一直连不上github,则尝试判断距离上次更新的时间是否已经很长 time_since_last_update = datetime.now() - datetime.strptime( ver_time, "%Y.%m.%d") if time_since_last_update.days >= 7: msg = f"无法访问github确认是否有新版本,而当前版本更新于{ver_time},距今已有{time_since_last_update},很可能已经有新的版本,建议打开目录中的[网盘链接]看看是否有新版本,或者购买自动更新DLC省去手动更新的操作\n\n(如果已购买自动更新DLC,就无视这句话)" logger.info(color("bold_green") + msg) if is_first_run( f"notify_manual_update_if_can_not_connect_github_v{now_version}" ): win32api.MessageBox(0, msg, "更新提示", win32con.MB_ICONINFORMATION) webbrowser.open(config.netdisk_link)
def check_update_on_start(config: CommonConfig): try: if is_run_in_github_action(): logger.info("当前在github action环境下运行,无需检查更新") return if not config.check_update_on_start and not config.auto_update_on_start: logger.warning("启动时检查更新被禁用,若需启用请在config.toml中设置") return ui = get_update_info(config) if config.check_update_on_start: try_manaual_update(ui) if config.auto_update_on_start: show_update_info_on_first_run(ui) except Exception as err: logger.error( f"检查版本更新失败(这个跟自动更新没有任何关系),大概率是访问不了github导致的,可自行前往网盘查看是否有更新, 错误为{err}" + color("bold_green") + f"\n(无法理解上面这段话的话,就当没看见这段话,对正常功能没有任何影响)" ) # 如果一直连不上github,则尝试判断距离上次更新的时间是否已经很长 time_since_last_update = datetime.now() - datetime.strptime(ver_time, "%Y-%m-%d") if time_since_last_update.days >= 7: msg = f"无法访问github确认是否有新版本,而当前版本更新于{ver_time},距今已有{time_since_last_update},很可能已经有新的版本,建议打开目录中的[网盘链接]看看是否有新版本,或者购买自动更新DLC省去手动更新的操作\n\n(如果已购买自动更新DLC,就无视这句话)" logger.info(color("bold_green") + msg) if is_first_run(f"notify_manual_update_if_can_not_connect_github_v{now_version}"): win32api.MessageBox(0, msg, "更新提示", win32con.MB_ICONINFORMATION) webbrowser.open("https://fzls.lanzous.com/s/djc-helper")
def update(args, uploader): logger.info("需要更新,开始更新流程") try: # 首先尝试使用增量更新文件 patches_range = uploader.latest_patches_range() logger.info(f"当前可以应用增量补丁更新的版本范围为{patches_range}") can_use_patch = not need_update(args.version, patches_range[0]) and not need_update( patches_range[1], args.version) if can_use_patch: logger.info(color("bold_yellow") + "当前版本可使用增量补丁,尝试进行增量更新") update_ok = incremental_update(args, uploader) if update_ok: logger.info("增量更新完毕") return else: logger.warning("增量更新失败,尝试默认的全量更新方案") except Exception as e: logger.exception("增量更新失败,尝试默认的全量更新方案", exc_info=e) # 保底使用全量更新 logger.info(color("bold_yellow") + "尝试全量更新") full_update(args, uploader) logger.info("全量更新完毕") return
def try_set_console_window_mode(show_mode: int, mode_name: str, mode_enabled: bool): """ 调用win32gui.ShowWindow设置当前cmd所在窗口的显示模式,可选值为[win32con.SW_MAXIMIZE, win32con.SW_MINIMIZE] """ # 判断是否需要尝试修改为对应窗口模式 if not mode_enabled: logger.info( color("bold_cyan") + f"当前未开启 {mode_name} 配置,将不尝试{mode_name}") return # 开始设置 logger.info(color("bold_cyan") + f"当前已开启 {mode_name} 配置,将尝试{mode_name}") current_pid = os.getpid() parents = get_parents(current_pid) # 找到所有窗口中在该当前进程到进程树的顶端之间路径的窗口 candidates_index_to_hwnd = {} def max_current_console(hwnd, argument): _, pid = win32process.GetWindowThreadProcessId(hwnd) if pid in parents: # 记录下他们在进程树路径的下标 argument[parents.index(pid)] = hwnd # 遍历所有窗口 win32gui.EnumWindows(max_current_console, candidates_index_to_hwnd) # 排序,从而找到最接近的那个,就是我们所需的当前窗口 indexes = sorted(list(candidates_index_to_hwnd.keys())) current_hwnd = candidates_index_to_hwnd[indexes[0]] win32gui.ShowWindow(current_hwnd, show_mode)
def auto_update(): args = parse_args() change_title("自动更新DLC") logger.info( color("bold_yellow") + f"更新器的进程为{os.getpid()}, 代码版本为{now_version}") logger.info( color("bold_yellow") + f"需要检查更新的小助手主进程为{args.pid}, 版本为{args.version}") # note: 工作目录预期为小助手的exe所在目录 if args.cwd == invalid_cwd: logger.error( "请不要直接双击打开自动更新工具,正确的用法是放到utils目录后,照常双击【DNF蚊子腿小助手.exe】来使用,小助手会自行调用自动更新DLC的" ) os.system("PAUSE") return logger.info(f"切换工作目录到{args.cwd}") os.chdir(args.cwd) uploader = Uploader() # 进行实际的检查是否需要更新操作 latest_version = uploader.latest_version() logger.info(f"当前版本为{args.version},网盘最新版本为{latest_version}") if need_update(args.version, latest_version): update(args, uploader) start_new_version(args) else: logger.info("已经是最新版本,不需要更新")
def take_guanhuai_gift(ctx): cfg = self.cfg.vip_mentor # 确认使用的角色 server_id, roleid = "", "" if cfg.guanhuai_dnf_server_id == "": logger.warning("未配置会员关怀礼包的区服和角色信息,将使用道聚城绑定的角色信息") logger.warning( color("bold_cyan") + "如果大号经常玩,建议去其他跨区建一个小号,然后不再登录,这样日后的关怀活动和集卡活动都可以拿这个来获取回归相关的领取资格" ) else: if cfg.guanhuai_dnf_role_id == "": logger.warning( f"配置了会员关怀礼包的区服ID为{cfg.guanhuai_dnf_server_id},但未配置角色ID,将打印该服所有角色信息如下,请将合适的角色ID填到配置表" ) self.djc_helper.query_dnf_rolelist( cfg.guanhuai_dnf_server_id) else: logger.info("使用配置的区服和角色信息来进行领取会员关怀礼包") server_id, roleid = cfg.guanhuai_dnf_server_id, cfg.guanhuai_dnf_role_id if guanhuai_distinctActive == "0": logger.warning( color("bold_cyan") + "本次会员关怀活动不允许获取资格和领取奖励的账号不同,因此若当前QQ未被判定为幸运玩家,则不会领取成功~") return _game_award(ctx, guanhuai_gift.act_name, guanhuai_gift.ruleid, area=server_id, partition=server_id, roleid=roleid)
def try_auto_resolve_captcha(self): try: self._try_auto_resolve_captcha() except Exception as e: msg = f"ver {now_version} {self.name} 自动处理验证失败了,出现未捕获的异常,请加群{config().common.qq_group}反馈或自行解决。请手动进行处理验证码" logger.exception(color("fg_bold_red") + msg, exc_info=e) logger.warning( color("fg_bold_cyan") + "如果稳定报错,不妨打开网盘,看看是否有新版本修复了这个问题~") logger.warning( color("fg_bold_cyan") + f"链接:{config().common.netdisk_link}")
def try_auto_resolve_captcha(self): try: self._try_auto_resolve_captcha() except Exception as e: msg = f"ver {now_version} 自动处理验证失败了,出现未捕获的异常,请加群966403777反馈或自行解决。请手动进行处理验证码" logger.exception(color("fg_bold_red") + msg, exc_info=e) logger.warning( color("fg_bold_cyan") + "如果稳定报错,不妨打开网盘,看看是否有新版本修复了这个问题~") logger.warning( color("fg_bold_cyan") + "链接:https://fzls.lanzous.com/s/djc-helper")
def exchange(startTime, endTime): waitTime = 0.001 show_progress_start_time = time.time() show_progress_delta = 0.1 update_user_info_start_time = time.time() update_user_info_delta = 30 * 60 latest_user_info = query_user_info() logger.info( color("bold_yellow") + f"本轮开始时间为{startTime},结束时间为{endTime},请求等待间隔为{waitTime}s,预计将尝试{(endTime - startTime).seconds // waitTime}次" ) while datetime.now() < startTime: now_time = time.time() if now_time - show_progress_start_time >= show_progress_delta: end = '' if now_time - update_user_info_start_time >= update_user_info_delta: latest_user_info = query_user_info() update_user_info_start_time = now_time end = '\n' print( "\r" + color("bold_cyan") + latest_user_info + color("bold_green") + f"当前时间为{datetime.now()}...,还需要等待{startTime - datetime.now()}才会开始尝试。", end=end) show_progress_start_time = now_time time.sleep(waitTime) print("\r", end='') futures = [] logger.info( f"开始准备发请求,现在时间为{datetime.now()},将以{waitTime}s的尝试间隔,一直尝试到{endTime}或成功抢到" ) index = 0 while datetime.now() < endTime: _work_start_time = time.time() index += 1 futures.append(pool.apply_async(do_exchange, [index])) _work_used = time.time() - _work_start_time if _work_used < waitTime: time.sleep(waitTime - _work_used) for future in futures: res = future.get() if res['success']: logger.info(color("bold_yellow") + "抢到啦~") logger.info(color("bold_cyan") + f"本轮尝试已完成,总计进行{index}次请求\n")
def show_head_line(msg, msg_color=color("fg_bold_green")): char = "+" line_length = 80 # 按照下列格式打印 # +++++++++++ # + test + # +++++++++++ logger.info(get_meaningful_call_point_for_log()) logger.warning(char * line_length) logger.warning(char + msg_color + padLeftRight(msg, line_length - 2) + color("WARNING") + char) logger.warning(char * line_length)
def show_head_line(msg, msg_color=None): char = "+" line_length = 80 # 按照下列格式打印 # +++++++++++ # + test + # +++++++++++ if msg_color is None: msg_color = color("fg_bold_green") logger.warning(char * line_length) logger.warning(char + msg_color + padLeftRight(msg, line_length - 2) + color("WARNING") + char) logger.warning(char * line_length)
def clean_dir_to_size(dir_name: str, max_logs_size: int = 1024 * MiB, keep_logs_size: int = 512 * MiB): # 检查一下是否存在目录 if not os.path.isdir(dir_name): return hrs = human_readable_size logger.info(color("bold_green") + f"尝试清理日志目录({dir_name}),避免日志目录越来越大~") logs_size = get_directory_size(dir_name) if logs_size <= max_logs_size: logger.info( f"当前日志目录大小为{hrs(logs_size)},未超出设定最大值为{hrs(max_logs_size)},无需清理") return logger.info( f"当前日志目录大小为{hrs(logs_size)},超出设定最大值为{hrs(max_logs_size)},将按照时间顺序移除部分日志,直至不高于设定清理后剩余大小{hrs(keep_logs_size)}" ) # 获取全部日志文件,并按照时间升序排列 logs = list(pathlib.Path(dir_name).glob('**/*')) def sort_key(f: pathlib.Path): return f.stat().st_mtime logs.sort(key=sort_key) # 清除日志,直至剩余日志大小低于设定值 remaining_logs_size = logs_size remove_log_count = 0 remove_log_size = 0 for log_file in logs: stat = log_file.stat() remaining_logs_size -= stat.st_size remove_log_count += 1 remove_log_size += stat.st_size os.remove(f"{log_file}") logger.info( f"移除第{remove_log_count}个日志:{log_file.name} 大小:{hrs(stat.st_size)},剩余日志大小为{hrs(remaining_logs_size)}" ) if remaining_logs_size <= keep_logs_size: logger.info( color("bold_green") + f"当前剩余日志大小为{hrs(remaining_logs_size)},将停止日志清理流程~ 本次累计清理{remove_log_count}个日志文件,总大小为{hrs(remove_log_size)}" ) break
def show_unexpected_exception_message(e: Exception): from config import Config, config time_since_release = get_now() - parse_time(ver_time, "%Y.%m.%d") cfg = Config() try: cfg = config() except: pass msg = f"ver {now_version} (发布于{ver_time},距今已有{time_since_release.days}天啦) 运行过程中出现未捕获的异常,请加群{cfg.common.qq_group}反馈或自行解决。" + check_some_exception( e) logger.exception(color("fg_bold_yellow") + msg, exc_info=e) logger.warning(color("fg_bold_cyan") + "如果稳定报错,不妨打开网盘,看看是否有新版本修复了这个问题~") logger.warning(color("fg_bold_cyan") + "如果稳定报错,不妨打开网盘,看看是否有新版本修复了这个问题~") logger.warning(color("fg_bold_cyan") + "如果稳定报错,不妨打开网盘,看看是否有新版本修复了这个问题~") logger.warning(color("fg_bold_green") + "如果要反馈,请把整个窗口都截图下来- -不要只截一部分") logger.warning( color("fg_bold_yellow") + "不要自动无视上面这三句话哦,写出来是让你看的呀<_<不知道出啥问题的时候就按提示去看看是否有新版本哇,而不是不管三七二十一就来群里问嗷") logger.warning(color("fg_bold_cyan") + f"链接:{cfg.common.netdisk_link}") if run_from_src(): show_head_line( "目前使用的是源码版本,出现任何问题请自行调试或google解决,这是使用源码版本的前提。另外,在出问题时,建议先尝试更新依赖库,确保与依赖配置中的版本匹配。", color("bold_yellow"))
def run_test(mode): lr = ql.login(acc.account, acc.password, login_mode=mode, name=account.name) # lr = ql.qr_login(login_mode=mode, name=account.name) logger.info(color("bold_green") + f"{lr}")
def filter_unused_params(urlRendered): originalUrl = urlRendered try: path = "" if urlRendered.startswith("http"): if '?' not in urlRendered: return urlRendered idx = urlRendered.index('?') path, urlRendered = urlRendered[:idx], urlRendered[idx + 1:] parts = urlRendered.split('&') validParts = [] for part in parts: if part == "": continue k, v = part.split('=') if v != "": validParts.append(part) newUrl = '&'.join(validParts) if path != "": newUrl = path + "?" + newUrl return newUrl except Exception as e: logger.error("过滤参数出错了,urlRendered={}".format(originalUrl), exc_info=e) logger.error("看到上面这个报错,请帮忙截图发反馈群里~ 调用堆栈=\n{}".format(color("bold_black") + ''.join(traceback.format_stack()))) return originalUrl
def message_box(msg, title, print_log=True, icon=MB_ICONINFORMATION, open_url="", show_once=False, follow_flag_file=True, color_name="bold_cyan", open_image="", show_once_daily=False): get_log_func(logger.warning, print_log)(color(color_name) + msg) if is_run_in_github_action(): return from first_run import is_daily_first_run, is_first_run show_message_box = True if show_once and not is_first_run(f"message_box_{title}"): show_message_box = False if show_once_daily and not is_daily_first_run( f"daily_message_box_{title}"): show_message_box = False if follow_flag_file and exists_flag_file('.no_message_box'): show_message_box = False if show_message_box and is_windows(): win32api.MessageBox(0, msg, title, icon) if open_url != "": webbrowser.open(open_url) if open_image != "": os.popen(os.path.realpath(open_image))
def game_over(self): logger.info(color("bold_cyan") + f"游戏已经结束,共耗时:{datetime.now() - self.game_start_time}") self.notify('游戏结束') restart = QMessageBox.question(self, "游戏结束", "是否重新开始?") == QMessageBox.Yes if restart: self.restart(manual=False)
def init_pool(pool_size): if pool_size <= 0: return global pool pool = Pool(pool_size) logger.info(color("bold_cyan") + f"进程池已初始化完毕,大小为 {pool_size}")
def upload_to_lanzouyun(self, filepath, target_folder, history_file_prefix="", also_upload_compressed_version=False, only_upload_compressed_version=False) -> bool: if not only_upload_compressed_version: ok = self._upload_to_lanzouyun(filepath, target_folder, history_file_prefix) if not ok: return False if also_upload_compressed_version: make_sure_dir_exists('.cached') filename = os.path.basename(filepath) compressed_filepath = os.path.join( '.cached', self.get_compressed_version_filename(filename)) compressed_history_file_prefix = f"{self.compressed_version_prefix}{history_file_prefix}" logger.info( color("bold_green") + f"创建压缩版本并上传 {compressed_filepath}") # 创建压缩版本 with open(f"{filepath}", "rb") as file_in: with lzma.open(f"{compressed_filepath}", "wb") as file_out: file_out.writelines(file_in) # 上传 return self._upload_to_lanzouyun(compressed_filepath, target_folder, compressed_history_file_prefix) return True
def message_box(msg, title, print_log=True, icon=win32con.MB_ICONWARNING, open_url="", show_once=False, follow_flag_file=True): if print_log: logger.warning(color("bold_cyan") + msg) if is_run_in_github_action(): return from first_run import is_first_run show_message_box = True if show_once and not is_first_run(f"message_box_{title}"): show_message_box = False if follow_flag_file and exists_flag_file('.no_message_box'): show_message_box = False if show_message_box: win32api.MessageBox(0, msg, title, icon) if open_url != "": webbrowser.open(open_url)
def check_all_skey_and_pskey(cfg): if not has_any_account_in_normal_run(cfg): return _show_head_line("启动时检查各账号skey/pskey/openid是否过期") QQLogin(cfg.common).check_and_download_chrome_ahead() if cfg.common.enable_multiprocessing and cfg.is_all_account_auto_login(): logger.info(color("bold_yellow") + f"已开启多进程模式({cfg.get_pool_size()}),并检测到所有账号均使用自动登录模式,将开启并行登录模式") get_pool().starmap( do_check_all_skey_and_pskey, [ (_idx + 1, account_config, cfg.common) for _idx, account_config in enumerate(cfg.account_configs) if account_config.is_enabled() ], ) logger.info("全部账号检查完毕") else: for _idx, account_config in enumerate(cfg.account_configs): idx = _idx + 1 if not account_config.is_enabled(): # 未启用的账户的账户不走该流程 continue do_check_all_skey_and_pskey(idx, account_config, cfg.common)
def main(): change_title("集卡特别版") # 最大化窗口 logger.info("尝试调整窗口显示模式,打包exe可能会运行的比较慢") change_console_window_mode_async() logger.warning(f"开始运行DNF蚊子腿小助手 集卡特别版,ver={now_version} {ver_time},powered by {author}") logger.warning(color("fg_bold_cyan") + "如果觉得我的小工具对你有所帮助,想要支持一下我的话,可以帮忙宣传一下或打开付费指引/支持一下.png,扫码打赏哦~") # 读取配置信息 load_config("config.toml", "config.toml.local") cfg = config() if len(cfg.account_configs) == 0: raise Exception("未找到有效的账号配置,请检查是否正确配置。") check_proxy(cfg) init_pool(cfg.get_pool_size()) change_title("集卡特别版", multiprocessing_pool_size=cfg.get_pool_size()) show_multiprocessing_info(cfg) check_all_skey_and_pskey(cfg) # 正式进行流程 run(cfg) auto_send_cards(cfg) show_lottery_status("卡片赠送完毕后展示各账号抽卡卡片以及各礼包剩余可领取信息", cfg, need_show_tips=True) # 运行结束展示下多进程信息 show_multiprocessing_info(cfg)
def update_retry_data(retry_key: str, success_timeout: int, recommended_retry_wait_time_change_rate=0.125, debug_ctx=""): from dao import RetryData # 重新读取数据,避免其他进程已经更新过数据 db = load_db() raw_login_retry_data = db.get(retry_key, {}) login_retry_data = RetryData().auto_update_config(raw_login_retry_data) # 第idx-1次的重试成功了,尝试更新历史数据 cr = recommended_retry_wait_time_change_rate login_retry_data.recommended_first_retry_timeout = ( 1 - cr ) * login_retry_data.recommended_first_retry_timeout + cr * success_timeout login_retry_data.history_success_timeouts.append(success_timeout) db[retry_key] = to_raw_type(login_retry_data) save_db(db) if use_by_myself(): logger.info( color("bold_cyan") + f"(仅我可见){debug_ctx} 本次重试等待时间为{success_timeout},当前历史重试数据为{login_retry_data}" )
def show_game_result(self): blue_evaluted_score = self.evaluate(cell_blue, ignore_game_over=True) red_evaluted_score = -blue_evaluted_score self.label_blue_score.setText( f"{self.score(cell_blue)}({blue_evaluted_score})") self.label_red_score.setText( f"{self.score(cell_red)}({red_evaluted_score})") blue, red, winner = self.get_current_winner_info() winner_name = self.cell_name(winner) winner_evaluated_score = self.evaluate(winner, ignore_game_over=True) winner_avg = self.ai_to_avg_stat.get(winner, AvgStat()).avg() winner_counter[winner] += 1 avg_blue = self.ai_to_avg_stat.get(cell_blue, AvgStat()).avg() avg_red = self.ai_to_avg_stat.get(cell_red, AvgStat()).avg() logger.info( f"{self.cell_name(cell_blue)}={blue}, 胜利次数为{winner_counter[cell_blue]},平均落子时间为{avg_blue:.1f}" ) logger.info( f"{self.cell_name(cell_red)}={red}, 胜利次数为{winner_counter[cell_red]},平均落子时间为{avg_red:.1f}" ) logger.info( color("bold_yellow") + f"游戏已经结束,胜方为{winner_name},局面分为{winner_evaluated_score},胜方平均落子时间为{winner_avg:.1f},共耗时:{datetime.now() - self.game_start_time}" )
def query_info(): url = "http://dnf.api.yzz.cn/activity/getExchangeList" res = requests.get(url, headers=headers).json() heads = ["id", "名称", "积分", "启用", "库存", "已发放", "总计"] colSizes = [3, 25, 6, 6, 6, 6, 6] import datetime logger.info(color("bold_yellow") + str(datetime.datetime.now())) logger.info(tableify(heads, colSizes)) for item in res["data"]: cols = [ item["id"], item["prize_name"], item["point"], item["enable"], item["stock"], item["sent_num"], item["stock"] + item["sent_num"] ] logger.info(color("bold_green") + tableify(cols, colSizes))
def try_lottery_using_cards(self, print_warning=True): if self.enable_cost_all_cards_and_do_lottery(): if print_warning: logger.warning( color("fg_bold_cyan") + f"已开启抽卡活动({self.zzconfig.actid})消耗所有卡片来抽奖的功能,若尚未兑换完所有奖励,不建议开启这个功能" ) card_counts = self.get_card_counts() for name, count in card_counts.items(): self.lottery_using_cards(name, count) else: if print_warning: logger.warning( color("fg_bold_cyan") + f"尚未开启抽卡活动({self.zzconfig.actid})消耗所有卡片来抽奖的功能,建议所有礼包都兑换完成后开启该功能,从而充分利用卡片。" )
def get_server_ip() -> str: global current_chosen_server_ip debugFunc = logger.debug # 可取消下面这行来本地测试,显示调试日志 # debugFunc = logger.warning if current_chosen_server_ip == "": debugFunc(f"开始尝试选择可用的服务器: {server_ip_list},超时时间为{check_timeout}秒") # 按优先级选择第一个可用的服务器 for ip in server_ip_list: debugFunc("尝试连接服务器: " + ip) if is_server_alive(ip): current_chosen_server_ip = ip break debugFunc("连接失败") # 没有任何可用服务器时,取第一个 if current_chosen_server_ip == "": current_chosen_server_ip = server_ip_list[0] logger.warning(f"未发现任何可用服务器,将使用首个服务器 {current_chosen_server_ip}") debugFunc(color("bold_cyan") + f"已初始化服务器为 {current_chosen_server_ip}") # 上报选用的服务器ip increase_counter(ga_category="chosen_server_ip", name=current_chosen_server_ip) return current_chosen_server_ip
def login_with_account_and_password(): logger.info( color("bold_yellow") + "当前为自动登录模式,请不要手动操作网页,否则可能会导致登录流程失败") # 切换到自动登录界面 logger.info("等待#loginframe#ptlogin_iframe#switcher_plogin加载完毕") time.sleep(self.cfg.login.open_url_wait_time) WebDriverWait( self.driver, self.cfg.login.load_login_iframe_timeout).until( expected_conditions.visibility_of_element_located( (By.ID, 'switcher_plogin'))) # 选择密码登录 self.driver.find_element(By.ID, "switcher_plogin").click() # 输入账号 self.driver.find_element(By.ID, "u").send_keys(account) # 输入密码 self.driver.find_element(By.ID, "p").send_keys(password) # 发送登录请求 logger.info("等待一会,确保登录键可以点击") time.sleep(3) self.driver.find_element(By.ID, "login_button").click() # 尝试自动处理验证码 self.try_auto_resolve_captcha()
def maximize_console_sync(): logger.info( color("bold_cyan") + "准备最大化运行窗口,请稍候。若不想最大化,可在小助手目录创建 .no_max_console 文件。若想最小化,则可创建 .min_console 文件。" ) if os.path.exists(".no_max_console"): logger.info("不启用最大化窗口") return current_pid = os.getpid() parents = get_parents(current_pid) # 找到所有窗口中在该当前进程到进程树的顶端之间路径的窗口 candidates_index_to_hwnd = {} def max_current_console(hwnd, argument): _, pid = win32process.GetWindowThreadProcessId(hwnd) if pid in parents: # 记录下他们在进程树路径的下标 argument[parents.index(pid)] = hwnd # 遍历所有窗口 win32gui.EnumWindows(max_current_console, candidates_index_to_hwnd) # 排序,从而找到最接近的那个,就是我们所需的当前窗口 indexes = sorted(list(candidates_index_to_hwnd.keys())) current_hwnd = candidates_index_to_hwnd[indexes[0]] op = win32con.SW_MAXIMIZE if os.path.exists(".min_console"): op = win32con.SW_MINIMIZE logger.info("已启用最小化模式") win32gui.ShowWindow(current_hwnd, op)
def change_console_window_mode(cfg, disable_min_console=False): logger.info(color("bold_cyan") + "准备最大化运行窗口,请稍候。若想修改该配置,请前往配置工具调整该选项~") try_set_console_window_mode(win32con.SW_MAXIMIZE, "最大化窗口", cfg.common.enable_max_console) try_set_console_window_mode( win32con.SW_MINIMIZE, "最小化窗口", cfg.common.enable_min_console and not disable_min_console)