"""为什么每次 [待回复恢复] 之后都跟着 [页面校验] 点击前会话列表已变化? 定位器 _pending_rows_on_page 找到了行,click_session 用同一个 y 复核却不过。 两边的判据不一样,这里把 click_session 的三个子条件拆开单独打印,看是哪一个 把点击否掉的。纯读,不点击、不发送。 """ import json import os import sys sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) import wechat_bot as bot_module # noqa: E402 from wechat_bot import ( # noqa: E402 _AVATAR_FP_BYTES, _SESSION_FP_BYTES, _LEGACY_SESSION_FP_BYTES, ) def hamming(a: bytes, b: bytes) -> int: if len(a) != len(b) or not a: return -1 return (int.from_bytes(a, "big") ^ int.from_bytes(b, "big")).bit_count() def main() -> None: bot = bot_module.WeChatBot() bot.safe_window_mode = True bot.auto_activate_window = False if not bot.connect(activate=False, wait_if_missing=False): print("[-] 未挂载到企业微信窗口") return pending = dict(getattr(bot, "_pending_reply_sessions", {})) print(f"待回复任务 {len(pending)} 个\n") for key, state in pending.items(): target_fp = bytes.fromhex(key) print("=" * 72) print(f"任务 {key[:16]}… send_state={state.get('send_state')!r}") found = bot._find_pending_session(target_fp) if found is None: incomplete = getattr(bot, "_pending_scan_incomplete", False) print( f" _find_pending_session: 没找到" f"(扫描{'被时间预算截断,结论不可信' if incomplete else '已走完全部分页,确实不存在'})" ) continue _page, row_center = found print(f" _find_pending_session: 命中 row_center={row_center}") latest = bot.capture_session_list() if latest is None: print(" 重新截取列表失败") continue legacy = len(target_fp) == _LEGACY_SESSION_FP_BYTES if legacy: actual = bot._legacy_session_fingerprint(latest, row_center, row_center=True) fp_ok = actual == target_fp else: actual = bot._session_fingerprint(latest, row_center, row_center=True) fp_ok = bot._session_fp_matches(actual, target_fp) print(f" 条件1 指纹匹配 = {fp_ok}") if actual and len(actual) == _SESSION_FP_BYTES and not legacy: name_ok, name_d = bot._name_fp_matches( actual[_AVATAR_FP_BYTES:], target_fp[_AVATAR_FP_BYTES:] ) print( f" 头像距离={hamming(actual[:_AVATAR_FP_BYTES], target_fp[:_AVATAR_FP_BYTES])} " f"(容差 {bot._FP_HAMMING_TOL_NAMED}/{bot._FP_HAMMING_TOL}) " f"名称匹配={name_ok} 距离={name_d} " f"名称有效={bot._name_fp_is_substantive(actual[_AVATAR_FP_BYTES:])}" ) pair = tuple(sorted((actual.hex(), target_fp.hex()))) print(f" 别名已登记={pair in getattr(bot, '_live_session_fp_aliases', set())}") pending_state = bot._pending_reply_state(target_fp) allow_flat = bool( (pending_state or {}).get("requires_visual_proof", False) or bot._flat_session_is_known(target_fp) ) allow_unrounded = bool( len(target_fp) == _SESSION_FP_BYTES and (pending_state or {}).get("requires_visual_proof", False) and not bot._flat_session_rejected(target_fp) ) shape_ok = bot._is_real_conversation( latest, int(row_center), quiet=True, row_center=True, allow_flat=allow_flat ) print(f" 条件2 会话形态 = {shape_ok} (allow_flat={allow_flat})") print(f" 条件3 兜底放行 = {allow_unrounded}") verdict = fp_ok and (shape_ok or allow_unrounded) print(f" → click_session 会{'放行' if verdict else '取消这次点击'}") if __name__ == "__main__": main()