ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

python语言-密码登录自动化脚本软件代码-QZQ-2026-9-25 - 1

python语言-密码登录自动化脚本软件代码-QZQ-2026-9-25 - 1 import win32con import win32gui import pyautogui import time import threading import tkinter as tk import clipboard from pynput import keyboard as pk_keyboard pyautogui.FAILSAFE False # # 配 置 区 # LOGIN_WINDOW_TITLE 密码登录系统 # 登录窗口标题支持部分匹配 PASSWORD_FILE password_dict.txt # 密码字典文件 WAIT_AFTER_LOGIN 0.6 # 每次点登录后等待秒数 # 密码框序号按 y 从上到下排序后取第几个内层小矩形 # 你的日志里内层候选 # 候选[0] (350, 234) y234 → 若密码框在上填 1 # 候选[1] (350, 277) y277 → 若密码框在下填 2默认 PASSWORD_ENTRY_INDEX 2 # 登录按钮序号按 x 从左到右排序后取第几个 # Button[0] 左 (222,334) / Button[1] 中 (312,334) / Button[2] 右 (402,334) LOGIN_BUTTON_INDEX 1 # ---------- 登录结果判定 ---------- # 永远忽略的窗口标题完全相等 IGNORE_TITLES { , 操作程序, Default IME, MSCTFIME UI, Program Manager, Microsoft Text Input Application, Windows Input Experience, } # 标题含这些关键字一律忽略编辑器 / 浏览器 / 输入法 / 你的项目名 IGNORE_KEYWORDS ( main.py, PyCharm, Visual Studio, Code, Edge, Chrome, Firefox, DeepSeek, 密码解密原代码, ) # 明确表示登录失败的窗口标题关键字 FAIL_KEYWORDS ( 错误, 失败, error, Error, 无效, 不正确, 提示, 警告, Warning, ) # 明确表示登录成功的窗口标题关键字 SUCCESS_KEYWORDS ( 成功, 欢迎, 主界面, 主菜单, Success, Welcome, ) # root tk.Tk() root.title(操作程序) root.geometry(720x620) # ---------- 全局停止标志 ---------- stop_flag threading.Event() # # 日 志 输 出 # log_text tk.Text(root, height28, width88, font(Consolas, 9)) log_text.pack(pady5) def log(msg): print(msg) try: log_text.insert(tk.END, str(msg) \n) log_text.see(tk.END) root.update() except Exception: pass def log_sep(title): log( * 64) if title: log(f {title}) log( * 64) # # 空 格 键 停 止双保险 # def trigger_stop(source): if not stop_flag.is_set(): stop_flag.set() log(f 收到停止信号 (来源: {source}), 将尽快退出 ) else: log(f 再次收到停止信号 (来源: {source}) ) def on_global_key_press(key): try: if key pk_keyboard.Key.space: trigger_stop(pynput全局) except Exception as e: print(全局监听异常:, e) def start_global_listener(): try: listener pk_keyboard.Listener(on_presson_global_key_press) listener.daemon True listener.start() log([监听] pynput 全局空格监听已启动) except Exception as e: log(f[监听] pynput 启动失败: {e}) def on_tk_space(eventNone): trigger_stop(Tk窗口) root.bind_all(space, on_tk_space) root.bind_all(KeyPress-space, on_tk_space) # # 窗 口 查 找 与 激 活 # def find_login_window(title): log(f[查找窗口] 目标标题: {title}) hwnd win32gui.FindWindow(None, title) if hwnd: log(f[查找窗口] 精确匹配成功, hwnd{hwnd}) return hwnd log([查找窗口] 精确匹配失败, 改为模糊匹配...) found [] def cb(h, _): t win32gui.GetWindowText(h) if t and title in t: found.append((h, t)) win32gui.EnumWindows(cb, None) if found: for h, t in found: log(f[查找窗口] 模糊匹配到: hwnd{h} 标题{t}) return found[0][0] log([查找窗口] 未找到任何匹配窗口) return 0 def activate_window(hwnd): if not hwnd: return False try: if win32gui.IsIconic(hwnd): log([激活窗口] 窗口最小化, 先还原) win32gui.ShowWindow(hwnd, win32con.SW_RESTORE) win32gui.SetForegroundWindow(hwnd) time.sleep(0.2) cur win32gui.GetForegroundWindow() ok (cur hwnd) log(f[激活窗口] hwnd{hwnd} 当前前台{cur} 成功{ok}) return ok except Exception as e: log(f[激活窗口] 异常: {e}) return False # # 枚 举 子 控 件 # def enum_child_controls(hwnd): controls [] def cb(h, _): if not win32gui.IsWindowVisible(h): return controls.append(( h, win32gui.GetClassName(h), win32gui.GetWindowText(h), win32gui.GetWindowRect(h) )) win32gui.EnumChildWindows(hwnd, cb, None) return controls def dump_all_controls(hwnd): log_sep(f枚举窗口 hwnd{hwnd} 的子控件) controls enum_child_controls(hwnd) if not controls: log([枚举] 未枚举到任何可见子控件) return controls for i, (h, cls, txt, rect) in enumerate(controls): cx (rect[0] rect[2]) // 2 cy (rect[1] rect[3]) // 2 log(f [{i:02d}] hwnd{h:8} class{cls:10} text{txt} frect{rect} center({cx},{cy})) log(f[枚举] 共 {len(controls)} 个控件) return controls # # 定 位 输 入 框Tk 版只保留内层小矩形 # def find_tk_entries(hwnd, inner_max_width200): controls enum_child_controls(hwnd) button_rows [(r[1], r[3]) for (h, c, t, r) in controls if c Button] log(f[Tk输入框] Button 行 y 范围: {button_rows}) def is_button_row(rect): top, bottom rect[1], rect[3] for bt, bb in button_rows: if not (bottom bt or top bb): return True return False candidates [] for h, cls, txt, rect in controls: if cls ! TkChild: continue if is_button_row(rect): continue width rect[2] - rect[0] if width inner_max_width: log(f[Tk输入框] 跳过大容器 hwnd{h} width{width} rect{rect}) continue candidates.append((h, cls, txt, rect)) candidates.sort(keylambda c: (c[3][1], c[3][0])) log(f[Tk输入框] 候选 {len(candidates)} 个已按从上到下排序:) for i, (h, cls, txt, rect) in enumerate(candidates): cx (rect[0] rect[2]) // 2 cy (rect[1] rect[3]) // 2 log(f 候选[{i}] hwnd{h} rect{rect} center({cx},{cy})) return candidates def find_nth_tk_entry(hwnd, n): cands find_tk_entries(hwnd) if len(cands) n: log(f[Tk输入框] 数量不足 ({len(cands)} {n})) return None rect cands[n - 1][3] xy ((rect[0] rect[2]) // 2, (rect[1] rect[3]) // 2) log(f[Tk输入框] 选中第 {n} 个, 点击坐标{xy}) return xy # # 定 位 按 钮按 x 从左到右排序 # def find_nth_button(hwnd, n, keywords(登录, 登陆, 确定, Login)): buttons [c for c in enum_child_controls(hwnd) if c[1] Button] buttons.sort(keylambda c: c[3][0]) log(f[定位按钮] 共 {len(buttons)} 个 Button (已按从左到右排序)) for i, (h, cls, txt, rect) in enumerate(buttons): cx (rect[0] rect[2]) // 2 cy (rect[1] rect[3]) // 2 log(f Button[{i}] hwnd{h} text{txt} center({cx},{cy})) if not buttons: return None matched [b for b in buttons if any(k in b[2] for k in keywords)] target matched if matched else buttons if matched: log(f[定位按钮] 关键字匹配到 {len(matched)} 个) else: log([定位按钮] 关键字未匹配, 按从左到右顺序取) if len(target) n: log(f[定位按钮] 数量不足 ({len(target)} {n})) return None rect target[n - 1][3] xy ((rect[0] rect[2]) // 2, (rect[1] rect[3]) // 2) log(f[定位按钮] 选中第 {n} 个 (从左数), 点击坐标{xy}) return xy # # 登 录 结 果 判 定修正版 # def enum_clean_top_windows(exclude_hwndNone): 枚举所有可见顶层窗口过滤掉编辑器/浏览器/输入法等干扰 result [] def cb(h, _): if h exclude_hwnd: return if not win32gui.IsWindowVisible(h): return t win32gui.GetWindowText(h) if not t: return if t in IGNORE_TITLES: return if any(k in t for k in IGNORE_KEYWORDS): return result.append((h, t)) try: win32gui.EnumWindows(cb, None) except Exception as e: log(f[检测] 枚举顶层窗口异常: {e}) return result def check_login_result(hwnd, original_title): 返回: success → 登录成功 fail → 出现错误提示密码错 unknown → 无法判断 # ---- 1. 原窗口是否还活着 ---- if not win32gui.IsWindow(hwnd): log([检测] 原登录窗口已关闭 → 登录成功) return success # ---- 2. 原窗口标题是否变化 ---- try: title win32gui.GetWindowText(hwnd) except Exception: log([检测] 读取原窗口标题异常 → 视为成功) return success if title ! original_title: log(f[检测] 原窗口标题变为 {title} → 登录成功) return success # ---- 3. 枚举所有干净的顶层窗口 ---- others enum_clean_top_windows(exclude_hwndhwnd) log(f[检测] 当前其他可见窗口: {[t for _, t in others]}) # ---- 4. 是否有失败提示 ---- for h, t in others: if any(k in t for k in FAIL_KEYWORDS): log(f[检测] 发现错误提示窗口 {t} → 密码错误) try: win32gui.PostMessage(h, win32con.WM_CLOSE, 0, 0) time.sleep(0.2) except Exception: pass return fail # ---- 5. 是否有成功提示 ---- for h, t in others: if any(k in t for k in SUCCESS_KEYWORDS): log(f[检测] 发现成功窗口 {t} → 登录成功) return success # ---- 6. 无法判断 ---- return unknown # # 辅 助 操 作 # def interruptible_sleep(seconds, step0.05): end time.time() seconds while time.time() end: if stop_flag.is_set(): return False time.sleep(step) return True def click_at(xy, label): if not xy: log(f[点击] {label} 坐标为空, 跳过) return False log(f[点击] {label} ({xy[0]}, {xy[1]})) pyautogui.click(xy[0], xy[1]) time.sleep(0.1) return True def clear_edit(): log([清空] CtrlA - Delete) pyautogui.hotkey(ctrl, a) time.sleep(0.05) pyautogui.press(delete) time.sleep(0.05) # # 主 流 程 # def try_passwords(): stop_flag.clear() log_sep(开始执行 (按空格键可随时停止)) # ---------- 第一步登录窗口置前 ---------- log( 第一步: 把登录窗口置于最前) hwnd find_login_window(LOGIN_WINDOW_TITLE) if not hwnd: log(f!!! 未找到标题包含 {LOGIN_WINDOW_TITLE} 的窗口) return log(f窗口句柄: {hwnd}) if not activate_window(hwnd): log(!!! 激活登录窗口失败) return original_title win32gui.GetWindowText(hwnd) log(f窗口已激活, 原标题{original_title}) dump_all_controls(hwnd) if stop_flag.is_set(): log(!!! 收到停止信号, 中止) return # ---------- 第二步读取 txt 文件 ---------- log( 第二步: 读取 txt 文件) try: with open(PASSWORD_FILE, r, encodingutf-8) as f: passwords [ln.strip() for ln in f if ln.strip()] except FileNotFoundError: log(f!!! 未找到文件: {PASSWORD_FILE}) return except Exception as e: log(f!!! 读取文件异常: {e}) return log(f共读取 {len(passwords)} 条密码) for i, p in enumerate(passwords[:10], 1): log(f 第{i}条: {p}) if len(passwords) 10: log(f ... (剩余 {len(passwords) - 10} 条省略)) if not passwords: log(!!! 密码字典为空) return if stop_flag.is_set(): log(!!! 收到停止信号, 中止) return # ---------- 第三步定位密码输入框 ---------- log( 第三步: 定位密码输入框) edit_xy find_nth_tk_entry(hwnd, nPASSWORD_ENTRY_INDEX) if not edit_xy: log(!!! 未找到密码输入框) return log(f密码输入框坐标: {edit_xy}) # ---------- 第四步定位登录按钮 ---------- log( 第四步: 定位登录按钮) btn_xy find_nth_button(hwnd, nLOGIN_BUTTON_INDEX) if not btn_xy: log(!!! 未找到登录按钮) return log(f登录按钮坐标: {btn_xy}) if stop_flag.is_set(): log(!!! 收到停止信号, 中止) return # ---------- 第五步循环输入、登录 ---------- log( 第五步: 循环输入密码并登录) success_password None total len(passwords) for idx, pwd in enumerate(passwords, start1): if stop_flag.is_set(): log(f!!! 第 {idx} 轮开始前检测到停止信号, 退出循环) break log_sep(f尝试 {idx}/{total} 密码{pwd}) # 每轮开始前重新激活窗口 log([循环] 重新激活窗口) if not activate_window(hwnd): log([循环] !!! 激活失败, 跳过本次) continue if stop_flag.is_set(): log([循环] !!! 停止信号, 退出) break log([循环] 点击密码输入框) click_at(edit_xy, 密码输入框) log([循环] 清空输入框) clear_edit() log(f[循环] 复制密码到剪贴板: {pwd}) clipboard.copy(pwd) time.sleep(0.03) log([循环] CtrlV 粘贴) pyautogui.hotkey(ctrl, v) time.sleep(0.15) log([循环] 点击登录按钮) click_at(btn_xy, 登录按钮) log(f[循环] 等待 {WAIT_AFTER_LOGIN}s (按空格可打断)) if not interruptible_sleep(WAIT_AFTER_LOGIN): log([循环] !!! 等待期间被空格打断, 退出循环) break # 检测登录结果三态 result check_login_result(hwnd, original_title) if result success: log_sep(f!!! 登录成功! 密码 {pwd}) success_password pwd break elif result fail: log(f[循环] 密码 {pwd} 错误, 继续下一个) else: log([循环] 结果未知, 继续下一个) # 收尾 if success_password: log_sep(f结果: 登录成功, 密码{success_password}) elif stop_flag.is_set(): log_sep(已由用户按空格键停止) else: log_sep(全部密码已尝试完毕, 未检测到成功) # # 界 面 # btn_run tk.Button(root, text执行操作, commandtry_passwords, height2, width20) btn_run.pack(pady5) btn_clear tk.Button(root, text清空日志, commandlambda: log_text.delete(1.0, tk.END)) btn_clear.pack(pady2) start_global_listener() log([提示] 按空格键可停止。) log(f[配置] 密码框序号{PASSWORD_ENTRY_INDEX} (从上往下), f登录按钮序号{LOGIN_BUTTON_INDEX} (从左往右)) log(f[配置] 每次登录等待 {WAIT_AFTER_LOGIN}s) root.mainloop()
返回列表