Files
kefu/wechat_rpa/tmp/probe_resume_click.py
T
2026-08-18 17:25:22 +08:00

99 lines
4.1 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""为什么每次 [待回复恢复] 之后都跟着 [页面校验] 点击前会话列表已变化?
定位器 _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()