微信群发助手
> 版本 v1.0.0 | 许可 MIT | 适用于 PC 微信 4.x(Windows)
>
> ⚠️ 使用前必读:本技能通过模拟鼠标键盘操作微信客户端实现批量发送。自动化操作可能触发微信风控,
> 请控制单日发送量、拉长间隔,并自行承担账号风险。仅建议用于你自己有权触达的联系人(已同意接收的客户/学员),
> 严禁用于骚扰、营销群发陌生人。删除好友操作不可逆,必须人工确认名单后执行。
快速上手(学员版,5 步跑通)
| 步骤 | 做什么 | 命令/动作 |
|---|---|---|
| 1 | 装环境 | 安装 Python 3.11+(勾选 Add to PATH),然后 pip install pillow numpy rapidocr_onnxruntime |
| 2 | 备名单 | 在工作目录建 send_list.json,格式 [{"group":"A","name":"微信备注名原样"}] |
| 3 | 准备微信 | 登录 PC 微信 4.x,主窗口不要最大化(建议 1000~1200 宽),自己别动电脑 |
| 4 | 试发 3 人 | python blast_all.py TEST 3,日志出现 ✓命中 才算通 |
| 5 | 跑全量 | python blast_all.py ALL(中断后重跑同一条命令会自动续发) |
三条保命原则:① 跑之前把电脑交出来,不要碰键鼠;② 先 TEST 再 ALL;③ 删除好友永远先出名单、人工确认再执行。
用途
按名单(Excel/JSON)给微信好友批量自动发送同一条文案。每条消息经过:搜索联系人 → 点下拉条目进聊天 → 粘贴文案 → 回车发送 → OCR验证气泡真实发出。已发名单自动跳过(断点续发+防重),连续失败自动熔断。
核心脚本:
- scripts/sender_gq.py —— 发送引擎(搜索/人名匹配/防重/OCR验证/窗口唤醒)
- scripts/blast_all.py —— 全量驱动(断点续跑 + 两类熔断保护 + 锁屏等待)
- scripts/sender6.py —— 公共库(复检侧共用的窗口枚举/截图/OCR)
依赖:Python 标准库 + rapidocr-onnxruntime + Pillow + numpy(全部免费)。
> 换电脑/换机:直接跑 python build_transfer_pack.py,会在桌面生成迁移包 zip,
> 里面含全套脚本 + 名单账本 + 技能包 + 迁移说明 + 一键环境检查.bat。
> 新电脑只需装 Python + 三个依赖库 + 微信 PC 4.x,然后把工作目录放任意位置即可。
使用流程
1. 名单准备
把名单写入工作目录 send_list.json,格式:
[{"group": "A", "name": "张三要学习"}, {"group": "B", "name": "李四要学习"}]
- name 用微信备注名原样(含"要学习"等后缀没关系,脚本会自动处理)
- 从 Excel 提取时用 openpyxl 读指定 sheet 的列,按 norm() 去重后写入
- 同名重复记录会被 norm 去重 + 聊天区防重双重拦截
2. 开跑前硬性检查(缺一不可)
- 用户确认电脑完全交出:用户在用电脑时严禁开跑(Chrome 等前台窗口会抢键盘焦点,输入窜窗、点错地方)。必须用户明确说"开跑/去睡了"。
- 微信已登录、主窗口在桌面上可见(最小化也行,脚本会自动还原)。
- 工作目录正确(send_list.json、sent_names.json、send_log6.txt 都在这里)。
3. 试发验证(每次改完脚本或换名单必做)
python blast_all.py TEST 3 # 先发3人,日志确认出现 ✓命中标题
看日志确认:搜索词进框 → 点中条目 → 标题匹配 → 文案进输入框 → 气泡验证通过。有 ⚠/❌ 先修再跑全量。
4. 全量发送
python blast_all.py ALL # 断点续跑:已发过的自动跳过
- 用受管后台任务方式跑(
run_in_background),不要用 Start-Process 游离进程(实测几分钟内被系统无声杀死) - 断点续发:中断后重跑同一命令,账本里
ok/ok-already的自动跳过 - 熔断保护(两类):①搜索词未进框=真故障,连续 15 人停机;②下拉无匹配=名字短/不在通讯录属正常,连续 60 人才停机
- 锁屏自动等待:检测到锁屏会每 30 秒检查一次,解锁后自动起跑
5. 出报告
读 blast_ledger.json 统计 ok/ok-already/skip/fail;skip 和 fail 名单进 blast_candidates.json(非好友复检的来源池)。report_gq.py 可生成战报到桌面。
6. 非好友复检清理(三步走,绝不自动删人)
set CHECK_ONLY=1 && python recheck_run.py ALL # 1. 只检查,生成 victim_list.txt
# 2. 用户过目 victim_list.txt 确认
python del_confirmed.py # 3. 确认后才执行删除
删除不可逆。必须先出名单给用户确认,绝不能自动删。
铁律(每一条都是踩坑换来的,违反必翻车)
- 禁用 ESC 键:微信无弹层时按 ESC = 整窗缩进托盘,随后所有操作错位——这是"微信假死/消失"的元凶。关弹层用点击空白处或 WM_CLOSE。
- 禁止改窗口尺寸/位置(SetWindowPos):会导致微信直接退出。只用 GetWindowRect 读实际位置自适应。
- UIA 不可用:微信 Qt 纯自绘,控件树只有空壳节点,pywinauto/uiautomation 拿不到任何控件。别再试这条路。
- DPI 感知:脚本开头必须
SetProcessDpiAwareness(2),全部用物理坐标;否则 125% 缩放下点击偏移 ~60px。 - 抓图用 PrintWindow(PW_RENDERFULLCONTENT),ImageGrab 屏幕抓图会拿到陈旧画面导致误判;但独立下拉弹层 PrintWindow 抓不到主窗口内容,弹层要按屏幕区域抓或抓弹层自己的 hwnd。
- RapidOCR 对超扁长条图(高约<100px)返回空:OCR 前把小图垫白边放大(pad 到 ≥900×300),脚本内
ocr_padded()已实现。 - 搜索词必须原样(name_queries,2026-09-23 重大修复):微信按原始文本匹配搜索词,norm 小写化+删符号会破坏连续性——WU_Example 搜 wujunne(下划线没了)搜不到、某某 搜 人琴 搜不到、"要学习"夹中间(某好友B要学习大学生)去掉后 某好友B大学生 不是连续子串也搜不到。正确顺序:原样 base → 原样全名 → 按"要学习"split 的分段 → norm 版兜底 → 短词(原样+norm),单人上限 8 个查询词防卡死。norm 只用于匹配(name_match),绝不能用于构造搜索词。
- 匹配去噪(name_match):比对标题时两边都去掉"要学习",规避备注后缀干扰。
- 独立聊天小窗:微信有时把聊天弹成独立小窗(标题=联系人名),压在主窗口上抢点击和键盘,导致后续全部"搜索词未进框"。对策:点开联系人后枚举标题≠'微信'的 Qt 可见窗口——标题匹配则在小窗里直接发送,不匹配的 WM_CLOSE 关掉;每人发完立即清掉所有小窗。
- 防重双保险:
sent_names.json(norm 后名字)+ 打开聊天后 OCR 检测聊天区是否已有文案 MARK(检测到=已发过,跳过不重发)。返回 'ok-already' 也计入。
10b. 发送后气泡验证防误杀(2026-09-23):消息实际发出但 OCR 没验证到(渲染延迟/滚动)会被误记 fail——实测 某客户A 已发出却记 fail。对策:扩大验证区 + 等 1.6s 重验 3 次;即便误记 fail,重跑时聊天区 MARK 防重检测会兜底,不会重复打扰。
10c. 防误发安全网(下拉条目时间戳检测):搜索无结果时下拉显示聊天列表(条目右侧带 10:xx 时间戳/[999+条]),脚本 OCR 会匹配到列表项误点开别人。对策:条目同行 ±18px 内出现\d{1,2}:\d{2}时间戳的一律不点。标题验证(铁律 8 的匹配)是最后防线。
10d. 熔断分两级(2026-09-23 定稿):恶性 fail(异常/文案未进框等系统性故障)连 6 次熔断;良性 skip(搜不到人)连 40 次才熔断。名单后段是"死名单重灾区"(已删好友/改名/提取乱码重复项如 Vaaf99n-Waaf99n 同人两条),每人烧 ~1 分钟,统一阈值会在死名单区反复停机。健康节奏参照:成功周期 ≈40 秒/人(看相邻---头行间隔),>60 秒说明在重试。
10d2. 死名单永久剔除、绝不重试:skip_counts.json 记录每人搜不到次数,≥2 直接拉黑不再进队列(否则每轮重头卡死)。教训:洗冤重置手不能重——按日志"标题未匹配"重置受害者时,会把死名单也放回(它们日志里也有类似记录),用户看着连败十几人以为又崩了。要重置就逐个名单确认(有下拉匹配截图证据的才重置);确认搜不到的(count≥1)宁可全置 2 剔除,漏的人走"待人工"清单。
10e. 剪贴板偶发写入失败:clip_write 返回 False 时 paste_verified 全部失败("搜索词未进框"连环出现)——偶发竞争,多轮重试即可恢复;诊断时给 clip_write 加 GetLastError 打印定位。
10f. 窗口尺寸漂移 = 全场崩溃(2026-09-23 下午重大事故):微信窗口被最大化后(1123→1938 宽),所有按窗口比例算的坐标全部偏移——搜索框/左侧栏/下拉是固定像素布局不随窗口缩放!搜索框点击 (0.175W,67) 在 1938 宽时偏到 339px。对策:搜索框点 (200,67)、验证区 (90,45,430,95)、下拉抓取 (0,40,560,460)、条目 x=l+260 全部固定像素;输入框/气泡验证区用比例(横跨聊天区,安全)。
10f2. 标题验证区起点必须实测(2026-09-23 傍晚重大bug,用户亲眼所见):聊天标题从 x≈372 就开始(1123 宽窗实测),旧区域 (400,20,1300,130) 切掉标题首字 → "某好友C"被 OCR 读成"寻之我幸" → 假性"标题未匹配" → 人已点开却跳过不粘贴。修复区域 (330,15,1450,85):y 上限 85 排除列表首行时间戳噪声;搜索框在 x100-310 也不会误入。教训:比例坐标和固定像素都会因列表列宽 flex 缩放而失准,改区域前必须 PrintWindow 抓全窗截图量出真实像素起点;离线回归(旧区 vs 新区 OCR 对比)30 秒就能验证。
10g. 小程序窗口劫持(WeChatAppEx.exe):搜索无结果时下拉显示网络结果(文字可与查询词完全相同,如"某好友D"),点了打开微信内置浏览器劫持焦点 → 后续点击/粘贴全进小程序 → 连环崩。对策:① pick_dropdown_entry 只点"联系人"分组内条目(OCR 认"联系人/最常使用"标题);"搜索网络结果/群聊/聊天记录/公众号"标题之下绝不点(群聊绝不点=防发错群);② send_one 开头 close_appex_windows()(枚举 WeChatAppEx.exe 可见窗口 WM_CLOSE);③ paste 失败时也清一次。
10h. 点空白的安全位置:关下拉点空白,三处雷区——聊天区中间(有小程序分享卡片,点了弹小程序)、标题栏(快速重试构成双击=切最大化)、左侧图标栏(底部有小程序面板按钮!)。安全位置:聊天标题栏右侧空白 (0.85W, 45)。 - 粘贴用纯 ctypes 写 CF_UNICODETEXT(utf-16-le+\0),搜狗输入法会拦截 keybd_event 字符键;粘贴后必须 OCR 读回验证,失败重试。
- 前台抢焦点:AttachThreadInput 方式抢前台;抢不到立即 ABORT 中止(说明用户在用电脑)。
- 键盘组合键顺序:Ctrl+A 清空 = Ctrl按下→A按下→A抬起→Ctrl抬起,顺序错了会输入字母"a"。
- 进程保活:每次发送前 find_main 检查微信;进程没了自动 Start-Process 拉起并处理登录页。Python 脚本自身加 faulthandler 落盘(fault.log)便于排查硬崩溃。
- 批量规模:单日同文案群发量大会触发微信风控,建议夜间跑、间隔拉长、单轮别超过 ~800 人;微信 4.1.15.12 实测对脚本操作整体耐受(26分钟40人零崩溃),但请勿并发多开。
- 搜索下拉弹层类名 = Qt51514QWindowToolSaveBits(2026-10-01 重大bug,误标126人"永久跳过"):find_popup 只按 'QWindowIcon' 过滤会把弹层漏掉 → 表现为永远"下拉无匹配"。必须同时兼容 'QWindowToolSaveBits'。主窗 PrintWindow 截图里看不到下拉 ≠ 下拉没出现——弹层是独立顶层窗口,判断下拉必须枚举弹层 hwnd 或全屏抓图(ImageGrab.grab)。
- 鼠标点击搜索框/左侧导航栏可能整体失效,但聊天列表点击仍有效(2026-10-01 实测):此时别下"微信假死"结论。用 Ctrl+F 激活搜索框(比点击稳)+ Ctrl+A 全选旧词再粘贴覆盖。分层测试:点聊天列表行 → 点左栏图标 → 点搜索框,逐层判断失效范围。
- 启动新批次前必须查杀残留 sender 进程(2026-10-01 事故:两个残留
sender_gq.py C 10进程与新进程并发跑数小时,互相抢焦点、交叉误标联系人)。查杀:Get-CimInstance Win32_Process -Filter "Name like 'python%'" | Where-Object {$_.CommandLine -like '*sender_gq*'} | ForEach-Object { Stop-Process -Id $_.ProcessId -Force }(别杀其他 python)。 - "搜索失效"误诊链(2026-10-01,浪费大半天):现象是"试发全部下拉无匹配",先后误诊为搜索索引损坏→重启微信→陷入登录循环→重启电脑,全都没用。真相 = ①弹层类名漏抓(铁律16)②残留进程并发(铁律18)。正确诊断顺序:全屏抓图看下拉是否真出现 → 枚举弹层 hwnd 抓弹层 OCR → 查并发 python 进程,三项都排除才考虑重启微信/电脑。
- 误标重置分级:因系统性 bug(如铁律16/18)期间标记的 skip 可以全量重置(备份后清空 skip_counts,防重靠 sent_names 账本不会重发已发);而零散期(无 bug 证据)的"搜不到"重置要手软,按铁律 10d2 处理。
免打扰后台采集通讯录(collect_bg.py,2026-09-28 实测)
场景:用户正在用电脑,需要全量采集通讯录(滚动+OCR)但不抢鼠标/不抢焦点。
四件套(缺一不可):
1. 恢复窗口不抢焦点:ShowWindow(H, 4)(SW_SHOWNOACTIVATE)。最小化窗口 PrintWindow=全黑图(OCR 读到 0 内容→误判"到底"),必须先恢复;恢复后窗口在用户浏览器 Z 序下面,用户无感。
2. 无鼠标点击:PostMessageW(H, WM_LBUTTONDOWN/UP, 1/0, lp),lp=客户区坐标 (y<<16)|x。可点左侧图标切页(通讯录=x35,y187)。
3. 后台滚轮:PostMessageW(H, WM_MOUSEWHEEL, wp, lp),wp=(delta&0xFFFF)<<16,lp 必须是屏幕坐标(写 0 消息会被 Qt 丢弃!),delta 负=向下;实测 delta±240=1 行。
4. 抓屏:PrintWindow 对非前台窗口有效(s6.grab_any 不变)。
节流坑:连续大量快速滚轮消息(如 120 次连发)后微信忽略后续滚轮——必须分组节奏(4 行/组,组间 OCR 检测)。单次事件 delta 响应上限约 2 行(mouse_event 版)。
方向反两次的血泪:step = 240 if rows<0 else -240 这种写法极易写反(正确:delta 负=向下,rows<0 即向下)。方向错了表现为"每次都采到头就提前停止/自救全部无效"。验证法:跑 TEST 后检查名字是否按字母序向下推进。
滚动边界:列表向上滚到"联系人 9636"分组头(sticky)处会被挡,PostMessage 滚不过分组头进不了星标/导航区——无妨,星标成员会重复出现在 A-Z 列表,不丢人。
主窗守卫:宽<700=掉登录,立即 sys.exit(2) 中止全链。
夜间无人值守发送(2026-09-28 两个新坑)
- 新会话第一条气泡在聊天区顶部:给从没聊过天的人发消息(如全量通讯录慰问),气泡显示在 y≈0.12-0.18H。发送后验证/防重检测的 crop 若从 0.22H/0.25H 起,全部误判 fail(实际已发出!)→ 重跑会重复打扰。两个 crop 都必须从 0.10H 起。症状:日志"发送后未验证到气泡, 标记fail"但聊天列表明明显示消息已发。曾因此 3/3 误判,靠开聊天抓全图实锤。
- 屏保/360壁纸全屏抢前台:夜间闲置触发"360壁纸"全屏 → focus_wechat 失败 → ABORT。修复:focus 失败时先模拟输入唤醒(mouse_event 移动 1-2px + SHIFT 键按下抬起)再重试一次 focus。发送主循环本身持续有输入不会触发屏保,但"每 50 人歇 3 分钟"后第一人要靠这个唤醒兜底。
最大化窗口与草稿残留(2026-09-29 四个新坑,全部实测定位)
- 窗口最大化 → 比例验证区切掉文案行首:输入框粘贴验证区原用
(0.32W, 0.78H),窗口最大化(1938宽)后 0.32W=620px,把输入框文案行首"开头问候"切在区域外 → OCR 只读到"我是使用者…" → 全员误判 fail(1123 宽时 0.32W=359 正常,所以以前一直没暴露)。修复:主窗验证区改(min(370, 0.26W), H-260, W, H)固定像素起点(聊天列表宽随窗口 flex 缩放,370 在 1123~1938 宽下都小于文案起点);独立小窗用(0.03W, 0.70H)。 - 常规 OCR 对输入框灰字返回 0 条:白底灰字文案在 DBNet 检测模型下直接失效(纯 resize 放大也没用,只有"发送"绿按钮能检出),灰度二值化(阈值140)后立即全部读出。修复:
ocr_text_multi()双路——常规 0 条时自动二值化重判;paste_verified加三路判定(zoom → 二值化 → 整窗兜底)。 - 输入框草稿残留 → 防重发误判"已发过"漏发:粘贴成功但发送前中断(或人工诊断粘贴未清)时,微信把草稿同步显示在聊天列表预览里;PrintWindow 偶发全黑 fallback 屏幕抓图时会把列表预览的草稿文字读进 MARK 判定 → ok-already 跳过。修复:①防重发/气泡验证区 y1 收到 0.78H 排除输入框;②防重发命中后等 1 秒重抓二次确认;③清理草稿必须搜索打开该联系人 → 点输入框 → Ctrl+A+Del → 验证列表预览无 [草稿](盲清当前窗口输入框不可靠,OCR 验证会假阴性)。
- 最小化还原后立即操作全部落空:SW_RESTORE 后窗口动画/渲染未就绪,立刻点搜索框+粘贴 → "搜索词未进框"。修复:还原后循环等待 find_main 且 rect 离开 -32000 且宽≥700 才返回。
诊断方法论:这类"全军覆没"先抓三样证据再改代码——① shots 目录最新截图(人到底点开没有、文案到底进没进);② 手动对已打开聊天跑一次带截图的粘贴实测(区分"真没进框" vs "OCR 误判");③ OCR 变体实验(原图/放大/二值化逐一对比)定位检测失效条件。OCR 显示 0 条 ≠ 文字不存在,先怀疑验证区坐标切割,再怀疑检测模型失效。
OCR 丢首字:采集名单的隐性污染(2026-09-30 实测定位,必查)
现象:全量采集后群发,队列整段"搜不到"(连 9 人全 skip、0 成功),看着像死名单,其实是采集时窄字被 OCR 吃掉。
铁证判据(一眼识别,写完名单先跑一次):
names_all.json 1977 个名字里,以"一"开头的只有 14 个
却有 24 个像 示例H/示例I/示例J/示例K/示例L/示例M/示例N/示例O —— 明显缺首字
另有 7 个以 - 或 | 开头:-示例G / -示例P / -示例R / -示例Q —— "一"被读成横线
"一"笔画少字形窄,RapidOCR 的 DBNet 检测框经常直接漏掉它。
修复(name_queries 第 6 轮,sender6.py / sender_gq.py 均已加):所有候选都搜不到后,追加 '一' + 去掉首符号的名字 再搜一轮。代价 8~16 秒/人,且只在前面全失败时触发。实测命中:示例H→一示例H、示例I→一示例I、-示例G→一颗糖。
配套必做:改完要重置被误判的跳过计数(skip_counts 里疑似丢字的条目),否则旧的"永久跳过"标记让这些人永远不再重试。脚本 reset_skips.py(只重置疑似丢字的,保留真死名字,自动备份原文件)。
更深一层——队列顺序也是效率杀手:采集顺序会把同类备注风格的号聚成一段(连续多个 OCR 花名/超长备注),顺序执行时长时间空转在同一段问题上。加 SHUFFLE=1 环境变量打散队列后,命中率立刻从 0/9 变成 4/5。排查"某段全失败"时,先怀疑名单本身,再怀疑队列顺序,最后才怀疑链路。
换机迁移(2026-09-30 实测,配套 build_transfer_pack.py)
一、写死路径必须改成自动推导(换机必崩的头号原因)
- sender6.py / sender_gq.py 顶部:BASE = r'C:\Users\<用户名>\...\wechat_extract' → BASE = os.path.dirname(os.path.abspath(__file__))
- report_gq.py 的桌面:winreg 读 Shell Folders\Desktop + expanduser('~/Desktop') 兜底(桌面可能被重定向)
- 战报话术用 ast 从 sender_gq.py 源码解析 SEND_TEXT,杜绝"战报话术与实发不一致"
二、绝对像素标定提成常量(集中一处,换机只改一个数)
- BUBBLE_X = 580(sender_gq.py / sender6.py 第 20 行)= 聊天区验证/防重裁剪起点,跳过左侧聊天列表(~507px)。换机/换分辨率/换 DPI 缩放必须重测:取气泡区最左边缘 x − 10。偏小 → OCR 读进左侧列表 → 关键词被拆断 → 误判 fail + 重复发。
- 其余为相对比例(0.85W / 0.65W / 0.87H)基本通用;固定像素点仅搜索框 (200,67)、标题栏 y=45。
三、迁移包(python build_transfer_pack.py → 桌面 zip,31 条目 ≈0.25MB)
1. 工作目录_wechat_extract/(脚本 + 名单 + 账本)→ 放任意路径即可
2. 技能包_wechat-mass-send/ → 拷到 C:\Users\<用户名>\.workbuddy\skills\wechat-mass-send\
3. 迁移说明.txt + 一键环境检查.bat(菜单:查环境/装依赖/试发2人/查进度)
四、新电脑前置:Python 3.11+(安装勾 Add to PATH)、pip install pillow numpy rapidocr_onnxruntime、微信 PC 4.x 同大版本、窗口别最大化(旧机实测 1064x1028)。
五、校准顺序:解压 → python sender_gq.py C 2 试发 2 人 → 成功即开跑;失败先调 BUBBLE_X,再微调搜索框/标题栏/输入框。
六、验证方法(打包后必做):解压到临时目录,子进程跑 import sender_gq 断言 BASE==解压目录 + 读到账本人数,再跑 report_gq.py 出报告即算通过。
七、千万别删 sent_names_gq.json(已发账本,删了全员重发)、skip_counts_gq.json、send_list_gq.json。
非好友扫描与删除清理(scanner7.py / deleter8.py)
识别铁证(微信系统提示,OCR 聊天区):
- "开启了朋友验证" = 对方已删除我(deleted)
- "被对方拒收" = 对方已拉黑我(blocked)
- 正常好友判据 = 能看到我发的 MARK 消息且无系统提示(ok);OCR 模糊一律 uncertain 留人工,绝不进删除队列
扫描三坑(scanner7):系统提示在聊天区顶部(消息少时我们的消息在最上面),y 要从 0.06H 起;x<395 会扫进左侧消息列表(列表预览含别人的"朋友验证"字样=污染);标题/下拉条目必须严格匹配完整名字,短词会开错人。
删除路径(deleter8,每步都有坑):
1. 聊天右上角 "..." 在 (0.952W, 66)——y=50 会点进标题栏空白
2. "..." 开的是右侧信息面板(查找聊天内容/免打扰/清空记录)——面板里没有删除项
3. 点面板头像 (0.715W, 147) → 资料页弹独立小窗,类名 Qt51514QWindowToolSaveBits——按 QWindowIcon 过滤永远抓不到,必须按 Qt51514 前缀匹配
4. 资料页上没有删除按钮!"删除联系人"在资料页右上角 "…" 菜单(410 宽窗时 x=336=0.82W, y=75;偏 14px 都点不中),菜单 = 263x360 ToolSaveBits 小窗(设置备注/朋友权限/推荐/星标/加入黑名单/删除联系人)
5. 确认弹窗:跨所有窗口 OCR 找"取消"+"删除"同时出现 → 点"删除"
6. 复搜验证:删完再搜应搜不到才算 ok
7. 安全设计:删前资料页 OCR 核对名字不符即 skip;每轮开始清理残留资料页窗(WM_CLOSE=取消,安全);主窗宽 <700 = 掉登录,立即中止全链不关机
文件清单
| 文件 | 作用 |
|---|---|
| send_list.json | 发送名单 [{group,name}] |
| sent_names.json | 已发名单(norm名),断点/防重 |
| send_log6.txt | 发送日志(成功/跳过/失败全程) |
| shots6/ | 每人关键步骤截图(排障用) |
| fault.log | faulthandler 崩溃遗言 |
| scanner7.py | 非好友扫描(打开聊天OCR分类,不发消息) |
| scan_results.json / scan_log.txt / shots_check/ | 扫描结果/日志/证据截图 |
| deleter8.py | 删除清理(铁证名单,资料页核对+复搜验证) |
| delete_log.txt / delete_shots/ | 删除记账/过程截图 |
| skip_counts.json | 搜不到计数(2次=永久跳过) |
| sender_gq.py | ★发送引擎(搜索/人名段匹配/防重/OCR验证/窗口唤醒) |
| blast_all.py | ★全量群发驱动(断点续跑 + 两类熔断 + 锁屏等待) |
| sender6.py | 公共库(窗口枚举/还原/截图/OCR,复检侧共用) |
| build_pool_all.py | 生成全量发送池 send_pool_all.json |
| recheck_run.py | ★非好友复检驱动(CHECK_ONLY=1 只出名单) |
| delete_final.py / deleter8.py | 非好友判定 + 删除执行体 |
| del_confirmed.py | ★确认后删除(读 victim_list.txt) |
| scanner7.py / scan_gq.py | 非好友扫描 / 聊天面板打开 |
| collect_bg.py | 免打扰全量通讯录采集(PostMessage 后台滚动+OCR,用户在用电脑时用这个) |
| clean_gq.py | 通讯录名单清洗 → send_pool_all.json |
| report_gq.py | 生成战报到桌面(桌面路径+话术全自动推导) |
| reset_skips.py | 重置被误判的跳过计数(自动备份) |
| build_transfer_pack.py | ★生成换机迁移包 zip(脚本+账本+技能包+说明+环境检查bat) |
| send_pool_all.json | ★全量发送池 |
| blast_ledger.json | ★★群发账本(断点核心,删了=全员重发) |
| blast_candidates.json | 搜不到/失败候选人池(复检来源) |
| recheck_ledger.json | ★复检账本(断点) |
| del_all_ledger.json / delete_final_ledger.json | 删除账本 |
| delete_shots/ | 删除过程截图(证据) |
★ 提速最快路径(2026-10-02 复盘定稿,跑长名单照抄这一套)
复盘:为什么"看起来半天没反应"(实测仅 20 人/小时,约为正常的 1/8)
| # | 根因 | 证据 | 修法 |
|---|---|---|---|
| 1 | 空闲守卫自伤(最大元凶) | GetLastInputInfo 是"全系统最后一次输入",脚本自己注入的点击/按键也会刷新它 → 每次发完必然从"自己那次点击"再等 60s,用户根本没碰电脑也照等。日志里 295 次假等待,使用者反馈"我没用电脑呀" | 加 mark_self() 标记自身注入;poll_input() 只认"真实用户输入"。见 sender_gq.py v2 守卫段 |
| 2 | 各处等待过肥 | 粘贴后等 2.2s、点条目等 2.5s、回车等 1.8s、每人固定间隔 10~18s | 压到 1.3 / 1.8 / 1.2 / 2.5~4.5s |
| 3 | OCR 成本高 | 每人 5~6 次 OCR,每次 1~3s(zoom2 放大 = 4 倍像素量) | RapidOCR(use_cls=False);ocr_zoom 默认 zoom 2.0→1.6 |
| 4 | 每 50 人休息 3 分钟 | 1225 人 = 25 次休息 = 75 分钟纯等待 | 休息 90s→45s |
| 5 | 进程静默掉线(今天 08:36 掉线 1 小时无人发现) | 自动化回合结束时,后台子进程被连带杀死,日志停在"等待空闲"那一行 | ①托管后台方式启动;②配"每2小时看门狗"自动化自检自愈 |
提速效果
- 改前:约 20 人/小时(大量假等待)
- 改后:目标 150~180 人/小时,健康节奏是单人 18~25 秒
- 判断标准:相邻
--- (n/N)头行间隔 >40 秒 就是在空转,去查日志
标准启动流程(照抄,工作目录必须是数据目录)
- 先查杀残留(否则双开打架):按命令行含
sender_gq过滤 python 进程并强制结束;再rm -f sender_gq.lock(残留锁会让新进程直接 exit 9)。 - 查账本进度:读
sent_names_gq.json条数,对比目标 1851。 - 微信就绪:主窗被最小化(位置约 -25600)用
ShowWindow(hwnd, 9)还原;没运行则启动Weixin.exe,登录小窗点窗口下部 75% 高度处。禁 ESC、禁改窗口尺寸。 - 托管后台启动:
SHUFFLE=1 python -u sender_gq.py C 600 > batch_auto.log 2>&1(打散队列,避免长时间卡在死名单区)。 - 3 分钟后读
send_log_gq.txt尾部 15 行,确认出现✓命中才算真的在发。
新增铁律(本次追加)
- 空闲守卫只认真实输入:任何"等用户空闲"的实现必须先把自己注入的键鼠事件排除,否则必然自伤成"每次必等 N 秒"。自检法:脚本自己点一下鼠标后立刻读空闲时间,若归零就是中了这个坑。
- 自动化回合会杀后台子进程:automation 场景里后台启动的进程,回合结束可能被连带杀死(今天静默掉线 1 小时)。必须配周期性"看门狗"自动化(进程不在就删锁重启),别指望单次启动能跑一整夜。
- 提速只能压"死等待",不能压"验证":等待时间随便压;但标题匹配、防重 OCR、气泡验证是防发错人/防重发的三道闸,压缩它们必翻车。要快就关 OCR 的 cls、降 zoom、减查询词数量。
- 队列打散且种子随启动时间变:固定种子会让每次重启都从同一段死名单区开头撞熔断,每轮白烧半小时。