106 lines
4.0 KiB
Python
106 lines
4.0 KiB
Python
"""只读诊断:同一个会话的档案指纹在多次采样之间是否稳定。
|
||
|
||
档案键 = 头像感知哈希(8B) + 名称哈希(32B),而 store.has_record() 是精确匹配。
|
||
只要指纹漂移,同一个联系人就会被当成“首次遇到”,从而丢弃复制到的聊天文字、
|
||
只靠截图回复。这里量化漂移幅度。
|
||
"""
|
||
|
||
import os
|
||
import sys
|
||
import time
|
||
|
||
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||
|
||
import numpy as np
|
||
|
||
import wechat_bot as bot_module
|
||
|
||
|
||
def hamming(a: bytes, b: bytes) -> int:
|
||
return (int.from_bytes(a, "big") ^ int.from_bytes(b, "big")).bit_count()
|
||
|
||
|
||
def main():
|
||
rounds = int(sys.argv[1]) if len(sys.argv) > 1 else 8
|
||
bot = bot_module.WeChatBot()
|
||
bot.safe_window_mode = True
|
||
bot.auto_activate_window = True
|
||
if not bot.connect(activate=False, wait_if_missing=False):
|
||
print("[-] 未挂载到企业微信窗口")
|
||
return
|
||
if not bot._ensure_visible():
|
||
print("[-] 企业微信未能切到前台")
|
||
return
|
||
print(
|
||
"容差: 头像 %d 位以内算同一人;名称使用模糊匹配"
|
||
% bot_module.WeChatBot._FP_HAMMING_TOL
|
||
)
|
||
|
||
samples = []
|
||
for index in range(rounds):
|
||
img = bot.capture_session_list()
|
||
selected_y = bot.detect_selected_row(img)
|
||
if selected_y < 0:
|
||
print(" 第 %d 次采样:未检测到选中行" % (index + 1))
|
||
time.sleep(0.4)
|
||
continue
|
||
avatar = bot._raw_session_fingerprint(img, selected_y, row_center=True)
|
||
name = bot._session_name_fingerprint(img, selected_y, row_center=True)
|
||
full = bot._session_fingerprint(img, selected_y, row_center=True)
|
||
samples.append((selected_y, avatar, name, full))
|
||
print(
|
||
" 第 %d 次采样:选中行 y=%-4d 头像=%s 名称=%s 完整键=%s"
|
||
% (index + 1, selected_y, avatar.hex(), name.hex()[:16] + "…", full.hex()[:16] + "…")
|
||
)
|
||
time.sleep(0.4)
|
||
|
||
if len(samples) < 2:
|
||
print("样本不足,无法比较。")
|
||
return
|
||
|
||
print("\n[行中心] y 取值: %s" % sorted({s[0] for s in samples}))
|
||
print("[头像哈希] 去重后 %d 种" % len({s[1] for s in samples}))
|
||
print("[名称哈希] 去重后 %d 种" % len({s[2] for s in samples}))
|
||
print("[完整档案键] 去重后 %d 种 <- 大于 1 就意味着同一会话会被反复当成新会话"
|
||
% len({s[3] for s in samples}))
|
||
|
||
base_y, base_avatar, base_name, _ = samples[0]
|
||
worst = 0
|
||
for y, avatar, name, _full in samples[1:]:
|
||
distance = hamming(base_avatar, avatar)
|
||
worst = max(worst, distance)
|
||
if distance:
|
||
print(
|
||
" 头像相对第 1 次漂移 %2d 位(y %d→%d)%s"
|
||
% (distance, base_y, y, " 超出容差!" if distance > bot_module.WeChatBot._FP_HAMMING_TOL else "")
|
||
)
|
||
print("[结论] 头像最大漂移 %d 位,容差 %d 位" % (worst, bot_module.WeChatBot._FP_HAMMING_TOL))
|
||
|
||
# 行中心偏移对指纹的影响:模拟 ±1~6 像素的行中心估算误差。
|
||
img = bot.capture_session_list()
|
||
selected_y = bot.detect_selected_row(img)
|
||
if selected_y >= 0:
|
||
anchor = bot._raw_session_fingerprint(img, selected_y, row_center=True)
|
||
print("\n[敏感度] 同一张图,仅把行中心挪动若干像素:")
|
||
for offset in (1, 2, 3, 4, 6, 8):
|
||
for sign in (-1, 1):
|
||
shifted = bot._raw_session_fingerprint(
|
||
img,
|
||
selected_y + sign * offset,
|
||
row_center=True,
|
||
)
|
||
print(
|
||
" 行中心 %+d px -> 头像漂移 %2d 位%s"
|
||
% (
|
||
sign * offset,
|
||
hamming(anchor, shifted),
|
||
" 超出容差!"
|
||
if hamming(anchor, shifted) > bot_module.WeChatBot._FP_HAMMING_TOL
|
||
else "",
|
||
)
|
||
)
|
||
|
||
|
||
if __name__ == "__main__":
|
||
main()
|