ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

基于Flask与UI自动化实现个人微信收款实时监听与自动充值系统

2026/8/16 19:56:20 拓冰建站 浏览量
基于Flask与UI自动化实现个人微信收款实时监听与自动充值系统

1. 项目概述:从个人收款到自动化充值的构想

最近在折腾一个个人小项目,需要实现一个“扫码即充值”的功能。说白了,就是用户扫一下我提供的二维码,钱到了我的个人微信,然后我的系统能自动识别这笔收款,并给用户的账户加上对应的余额或积分。听起来是不是有点像那些小游戏、小程序的“自助充值”入口?没错,这个需求在个人开发者、小工作室或者运营一些社群、工具站的场景里还挺常见的。比如你做了一个Unity打包的小游戏,想搞个内购;或者你搭了个Flask写的会员系统,需要个支付入口;再或者你只是单纯想把自己的微信收款码变成一个自动化的“收银台”。

这个项目的核心,绕不开两个东西:一个是微信,作为支付行为的发生地;另一个是本地服务,作为监听和处理支付结果的大脑。微信官方并没有为个人用户提供实时收款通知的API,所以这条路走不通。那怎么办?我们得自己“造轮子”,通过技术手段去“感知”收款的发生。主流思路无非两种:一是模拟用户行为,定时去检查微信账单;二是利用微信PC版的一些特性进行本地化监听。考虑到稳定性和实现的复杂度,后者——基于Windows平台上的微信PC客户端进行本地监听,并结合一个轻量的HTTP服务(比如用Flask框架快速搭建)来提供充值接口,成为了一个比较务实的选择。

整个流程可以简单理解为:用户在网页或应用里点击充值,我们的Flask服务生成一个唯一的订单和金额,并展示对应的微信收款码(金额已锁定)。用户扫码支付后,我们部署在Windows电脑上的监听程序,需要像一双“眼睛”一样,实时盯着微信的聊天窗口或账单变化,一旦发现匹配金额的收款,就立刻通知Flask服务:“钱到了!”。Flask服务随即确认订单,完成用户账户的充值。这中间涉及Windows自动化、图像/文字识别、网络通信和数据库操作等多个环节,每一个环节都有不少细节和坑等着我们去填。

2. 核心思路与技术选型:为什么是“本地监听+Flask服务”

当我们决定要自己实现这个监听时,首先得明确技术路径。为什么选择“本地监听微信PC客户端 + Flask HTTP服务”这个组合?这背后是需求、成本和可行性的权衡。

2.1 摒弃不切实际的幻想:官方API与第三方支付

首先,微信支付官方接口是为商户准备的,需要营业执照、对公账户等一系列资质,对于个人项目或小规模测试来说门槛太高。其次,市面上有一些聚合支付平台,但它们通常也要商户资质,并且会收取手续费,对于只是想跑通一个原型或者极低流量的个人项目,引入第三方反而增加了复杂度和成本。因此,利用现有的、每个人都能接触到的“个人微信收款码”就成了最直接、零成本的起点。

2.2 监听路径的抉择:文件监控 vs UI自动化

既然要监听个人微信,目标就是运行微信的这台电脑(通常是Windows日常办公机)。监听什么?有两个主要的数据源:

  1. 微信的本地存储文件:微信的聊天记录、包括收付款消息,理论上都加密存储在本地文件中(比如那个著名的WeChat Files目录)。但微信的文件存储格式和加密方式是不公开的,且经常随版本更新而变化,逆向工程难度大、稳定性差,极易因微信的一个小更新而失效。
  2. 微信PC客户端的用户界面:这是最直观的。收款成功后,微信PC版会在聊天窗口(文件传输助手或支付消息服务号)或弹出通知中显示收款详情,包含付款方昵称、金额和时间。

对比之下,从UI层面获取信息虽然听起来有点“笨”,但更稳定可靠。我们不需要破解微信的加密协议,只需要像用户一样“看到”屏幕上的信息即可。这就是UI自动化技术的用武之地。在Windows上,我们可以使用pyautoguipywinauto这类库来模拟鼠标键盘操作、定位窗口、捕获屏幕区域,再结合pytesseract(OCR光学字符识别)来读取图片中的文字,从而提取出收款金额和备注信息。

2.3 服务端的选择:Flask的轻量与敏捷

监听程序获取到收款信息后,需要通知给“大脑”——服务端。服务端需要做几件事:接收前端的充值请求、生成订单、提供收款码、接收监听程序的支付成功通知、更新用户账户。对于这样一个内部逻辑明确、并发量不会太高的系统,一个轻量级的Web框架足矣。

Flask以其极简的设计和强大的灵活性胜出。它没有Django那样“全家桶”式的沉重,用几行代码就能拉起一个HTTP服务。我们可以轻松地定义几个API端点:

  • POST /api/create_order: 创建充值订单。
  • GET /api/qrcode/<order_id>: 获取指定订单的收款码图片。
  • POST /api/notify_payment: (内部接口)供监听程序调用,通知支付成功。 用Flask能快速搭建原型,也方便后续扩展。数据库方面,为了简化,项目初期可以选用SQLite,它与Python天生集成,无需安装额外服务。如果考虑未来迁移或更复杂的查询,换成MySQL(通过pymysqlSQLAlchemy)也是平滑的。

2.4 整体架构图景

至此,我们的技术栈和架构清晰了:

  • 前端:一个简单的HTML页面,用于发起充值请求和展示二维码。可以用纯HTML/JS,也可以嵌套在微信小程序或Unity游戏内(通过WebView)。
  • 后端服务:基于Flask,提供RESTful API,处理订单逻辑,连接数据库。
  • 监听客户端:一个运行在微信PC客户端同一台Windows电脑上的Python脚本,使用UI自动化+OCR技术监控微信窗口。
  • 通信桥梁:监听客户端通过HTTP请求调用Flask服务的/api/notify_payment接口。

这个架构的优点是分工明确,每一部分都可以独立开发和调试。缺点是对运行微信的Windows电脑有依赖(需要常开),且UI自动化的稳定性需要精心设计来保障。

3. 核心模块拆解与实现细节

接下来,我们深入每个核心模块,看看具体怎么实现,以及会遇到哪些“坑”。

3.1 Flask服务端:订单与状态中枢

服务端是整个系统的大脑,它必须可靠地管理订单状态。一个订单的生命周期通常是:待支付->支付成功->已充值。要防止重复通知和并发问题。

首先,设计订单表。这里以SQLite为例,用Flask-SQLAlchemy来操作。

# app.py from flask import Flask, request, jsonify from flask_sqlalchemy import SQLAlchemy import datetime import hashlib app = Flask(__name__) app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///orders.db' app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False db = SQLAlchemy(app) class Order(db.Model): id = db.Column(db.Integer, primary_key=True) order_id = db.Column(db.String(32), unique=True, nullable=False) # 唯一订单号 amount = db.Column(db.Float, nullable=False) # 金额,单位元 status = db.Column(db.String(20), default='pending') # pending, paid, completed qrcode_data = db.Column(db.Text) # 收款码链接或Base64编码的图片数据 created_at = db.Column(db.DateTime, default=datetime.datetime.utcnow) paid_at = db.Column(db.DateTime) user_id = db.Column(db.String(50)) # 关联的用户ID def __repr__(self): return f'<Order {self.order_id} - {self.status}>' # 初始化数据库(首次运行) with app.app_context(): db.create_all()

创建订单的API需要生成唯一的订单号。一个简单的方法是使用“时间戳+随机数+用户ID”的哈希。

import time import random @app.route('/api/create_order', methods=['POST']) def create_order(): data = request.json user_id = data.get('user_id') amount = data.get('amount') if not user_id or not amount: return jsonify({'code': 400, 'msg': '缺少参数'}) # 生成订单号 raw = f'{user_id}{amount}{time.time()}{random.randint(1000,9999)}' order_id = hashlib.md5(raw.encode()).hexdigest()[:16] # 这里需要生成收款码。个人微信的固定收款码无法带金额,所以我们需要用“收款到手机”的方式。 # 实际上,更可行的方案是:生成一个包含金额和订单号的“备注”,让用户手动输入金额。 # 因此,qrcode_data 这里可以存储的是“收款人姓名”和“备注模板”。 # 例如:{"payee": "你的微信昵称", "note": "充值订单{order_id}"} # 前端展示时,提示用户“请向[你的微信昵称]转账[amount]元,备注填写[充值订单order_id]” qrcode_info = { "payee": "我的微信昵称", # 这个需要配置 "note_template": f"充值{order_id}", "amount": amount } new_order = Order( order_id=order_id, amount=amount, user_id=user_id, qrcode_data=json.dumps(qrcode_info), status='pending' ) db.session.add(new_order) db.session.commit() return jsonify({ 'code': 200, 'order_id': order_id, 'qrcode_info': qrcode_info, 'msg': '订单创建成功,请按提示转账' })

注意:个人微信收款码无法像商户一样动态生成带金额的二维码。因此,在实际操作中,通常采用“固定金额+唯一备注”的方式。即,前端明确告诉用户需要支付的确切金额,并要求在转账备注中填写我们提供的订单号。监听程序将同时核对“金额”和“备注”中的订单号,以确保匹配的准确性。这是整个方案中最关键的一环,务必在用户界面清晰提示。

支付成功回调接口是监听程序调用的内部接口,需要做安全校验(比如简单的Token验证)和幂等处理。

@app.route('/api/notify_payment', methods=['POST']) def notify_payment(): # 简单的Token验证,防止恶意调用 auth_token = request.headers.get('X-Auth-Token') if auth_token != 'YOUR_SECRET_TOKEN': # 替换为强密码 return jsonify({'code': 403, 'msg': 'Forbidden'}), 403 data = request.json amount = data.get('amount') note = data.get('note') # 转账备注 pay_time = data.get('pay_time') if not all([amount, note]): return jsonify({'code': 400, 'msg': '参数错误'}) # 从备注中提取订单号,这里假设备注格式为“充值{order_id}” import re match = re.search(r'充值(\w+)', note) if not match: return jsonify({'code': 400, 'msg': '备注格式不正确'}) order_id = match.group(1) # 查找订单 order = Order.query.filter_by(order_id=order_id).first() if not order: return jsonify({'code': 404, 'msg': '订单不存在'}) if order.status != 'pending': return jsonify({'code': 200, 'msg': '订单已处理'}) # 幂等返回 # 核对金额(允许微小误差,比如0.01元,应对微信显示格式) if abs(order.amount - float(amount)) > 0.01: return jsonify({'code': 400, 'msg': '金额不匹配'}) # 更新订单状态 order.status = 'paid' order.paid_at = datetime.datetime.utcnow() db.session.commit() # TODO: 触发实际充值逻辑,例如增加用户余额 # user = get_user(order.user_id) # user.balance += order.amount # db.session.commit() return jsonify({'code': 200, 'msg': '通知成功'})

3.2 监听客户端:UI自动化的眼睛

这是技术挑战最大的一部分。我们需要让程序自动检测微信窗口的收款消息。以下是一个基于pyautoguipytesseract的基础示例。

第一步:环境准备

pip install pyautogui pillow opencv-python-headless pytesseract

此外,还需要安装Tesseract-OCR的Windows应用程序,并将其安装目录(如C:\Program Files\Tesseract-OCR)添加到系统PATH环境变量中。pytesseract只是这个引擎的Python封装。

第二步:定位微信窗口我们的策略是:将微信PC版窗口固定放置在屏幕的特定位置(比如右上角),并保持“文件传输助手”或“微信支付”服务号的聊天窗口处于打开和激活状态。监听程序可以定期截图这个区域。

import pyautogui import time import cv2 import pytesseract from PIL import ImageGrab import json import requests # 配置区域:你需要根据自己屏幕分辨率调整 WECHAT_WINDOW_REGION = (1200, 100, 600, 800) # (left_x, top_y, width, height) FLASK_NOTIFY_URL = "http://localhost:5000/api/notify_payment" AUTH_TOKEN = "YOUR_SECRET_TOKEN" def capture_wechat_region(): """截图指定区域""" img = ImageGrab.grab(bbox=WECHAT_WINDOW_REGION) return cv2.cvtColor(np.array(img), cv2.COLOR_RGB2BGR) # 转为OpenCV格式 def extract_text_from_image(img): """使用OCR提取图片中的文字""" # 预处理图像以提高OCR精度:灰度化、二值化、去噪 gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 可以根据实际情况调整阈值或使用自适应阈值 _, thresh = cv2.threshold(gray, 180, 255, cv2.THRESH_BINARY_INV) # 将OpenCV图像转回PIL图像供pytesseract使用 text = pytesseract.image_to_string(Image.fromarray(thresh), lang='chi_sim+eng') return text

第三步:解析消息并匹配订单OCR提取出的文字是杂乱无章的,我们需要用规则去匹配关键信息。微信收款消息通常包含“收款”、“¥”、“元”、“来自”等关键词。

import re def parse_payment_from_text(text): """从文本中解析出支付金额和备注""" lines = text.split('\n') amount = None note = None amount_pattern = r'¥\s*(\d+\.?\d*)' # 匹配 ¥ 20.00 或 ¥20 note_pattern = r'备注[::]\s*(.+)' # 匹配 备注:充值ABC123 for line in lines: line = line.strip() # 找金额 amt_match = re.search(amount_pattern, line) if amt_match and not amount: amount = float(amt_match.group(1)) # 找备注 note_match = re.search(note_pattern, line) if note_match and not note: note = note_match.group(1).strip() return amount, note def monitor_loop(): """主监控循环""" last_processed = {} # 记录已处理的消息,防止重复通知。可以用时间或消息摘要做key。 while True: time.sleep(5) # 每5秒检查一次,避免CPU占用过高 try: img = capture_wechat_region() text = extract_text_from_image(img) amount, note = parse_payment_from_text(text) if amount and note: # 生成当前消息的简单指纹,例如“金额+备注+分钟数”,用于去重 minute_key = int(time.time() / 60) # 每分钟一个键 msg_fingerprint = f"{amount}_{note}_{minute_key}" if msg_fingerprint not in last_processed: print(f"检测到新收款: 金额{amount}元, 备注{note}") # 调用Flask回调接口 payload = { 'amount': amount, 'note': note, 'pay_time': time.strftime('%Y-%m-%d %H:%M:%S') } headers = {'X-Auth-Token': AUTH_TOKEN} resp = requests.post(FLASK_NOTIFY_URL, json=payload, headers=headers) if resp.status_code == 200: print("通知服务端成功") last_processed[msg_fingerprint] = True else: print(f"通知失败: {resp.text}") else: print("该收款已处理,跳过") except Exception as e: print(f"监控循环出错: {e}") time.sleep(10)

实操心得与避坑指南

  1. OCR精度是最大挑战:微信字体、屏幕缩放比例(建议设置为100%)、背景色都会影响识别率。需要大量调整图像预处理参数(如cv2.threshold的阈值)。可以尝试先检测消息气泡的轮廓,再对气泡区域进行OCR,能有效减少干扰。
  2. 窗口定位必须稳定:使用pyautoguigetWindowsWithTitle函数先通过窗口标题找到微信窗口,再获取其位置和尺寸,比写死坐标更健壮。
  3. 防重复处理机制至关重要:由于是轮询截图,同一笔收款消息可能会被识别多次。上面用的“分钟级指纹”是一种简单方法。更可靠的是记录已处理消息的“时间+金额”组合,并设置一个合理的过期时间(如30分钟)。
  4. 异常处理与日志:务必用try...except包裹核心逻辑,并记录详细的日志。这个脚本需要7x24小时运行,任何未处理的异常都可能导致监控停止。
  5. 性能考虑:截图和OCR是CPU密集型操作。循环中time.sleep的间隔很重要,太短了耗资源,太长了延迟高。5-10秒是一个比较平衡的区间。

3.3 前端交互:引导用户完成支付

前端页面可以非常简单,核心是引导用户完成“按指定金额转账并填写正确备注”的操作。

<!DOCTYPE html> <html> <head> <title>扫码充值</title> </head> <body> <h2>余额充值</h2> <input type="number" id="amount" placeholder="输入充值金额(元)" step="0.01"> <button onclick="createOrder()">生成支付指引</button> <div id="instructions" style="margin-top:20px; display:none;"> <p>请按以下步骤操作:</p> <p>1. 打开手机微信,点击右上角“+” -> “收付款” -> “向银行卡或手机号转账”。</p> <p>2. 在“转账给朋友”界面,选择“向手机号转账”,输入手机号 <strong id="payeePhone"></strong>。</p> <p>3. 输入金额:<strong id="payAmount"></strong> 元。</p> <p>4. <span style="color:red;">最重要的一步</span>:在“添加转账说明”中,<strong>必须填写</strong>:<code id="noteText"></code></p> <p>5. 完成转账。</p> <p>支付成功后,系统将在1分钟内自动到账。</p> <p>订单号:<code id="orderId"></code>,状态:<span id="orderStatus">等待支付</span></p> <button onclick="checkOrder()">检查到账状态</button> </div> <script> function createOrder() { const amount = document.getElementById('amount').value; if(!amount || amount <= 0) { alert('请输入有效金额'); return; } fetch('/api/create_order', { method: 'POST', headers: {'Content-Type': 'application/json'}, body: JSON.stringify({user_id: '当前用户ID', amount: parseFloat(amount)}) }) .then(r => r.json()) .then(data => { if(data.code === 200){ document.getElementById('payeePhone').textContent = '138****1234'; // 应从qrcode_info中获取 document.getElementById('payAmount').textContent = amount; document.getElementById('noteText').textContent = data.qrcode_info.note_template; document.getElementById('orderId').textContent = data.order_id; document.getElementById('instructions').style.display = 'block'; // 开始轮询订单状态 window.orderId = data.order_id; setTimeout(checkOrder, 30000); // 30秒后第一次检查 } else { alert('创建订单失败:' + data.msg); } }); } function checkOrder() { if(!window.orderId) return; fetch(`/api/order_status?order_id=${window.orderId}`) .then(r => r.json()) .then(data => { document.getElementById('orderStatus').textContent = data.status; if(data.status === 'paid' || data.status === 'completed'){ alert('充值成功!'); } else { setTimeout(checkOrder, 10000); // 未支付,10秒后再检查 } }); } </script> </body> </html>

这个前端页面没有动态生成二维码,而是给出了清晰的文字指引。因为个人微信无法生成带金额的动态码,所以指引用户进行“向手机号转账”操作并填写备注,是成功率最高的方式。务必用红色、加粗等方式强调备注必须正确填写,这是系统能识别订单的唯一依据。

4. 系统集成、部署与优化

将上述三个模块(Flask服务、监听脚本、前端页面)组合起来,并在Windows上稳定运行,还需要一些工程化的工作。

4.1 服务部署与自启动

Flask服务通常运行在开发服务器上,但用于生产环境不够稳定。我们可以使用WaitressGunicorn(在Windows上可用)作为WSGI服务器来运行Flask应用,性能更好。

pip install waitress

创建一个run.py

# run.py from app import app from waitress import serve if __name__ == '__main__': # 开发环境 # app.run(host='0.0.0.0', port=5000, debug=True) # 生产环境 serve(app, host='0.0.0.0', port=5000)

运行python run.py即可。

要让监听脚本和服务在Windows开机时自动启动,有两个方法:

  1. 创建计划任务:Windows搜索“任务计划程序”,创建基本任务。触发器设置为“计算机启动时”,操作为“启动程序”,选择你的Python解释器(如C:\Python39\python.exe)和脚本完整路径。
  2. 制作成Windows服务:使用pywin32nssm(Non-Sucking Service Manager)可以将Python脚本注册为系统服务,功能更强大,可以设置失败后重启。

4.2 通信安全与数据校验

目前的回调接口仅通过一个静态Token做简单验证,这在局域网或内网环境下可能够用。如果服务需要暴露在公网(强烈不建议直接暴露,风险极高),必须加强安全:

  • 使用HTTPS:通过Nginx反向代理并配置SSL证书。
  • 增加签名验证:监听程序在请求时,使用共享密钥对请求参数(如amount+note+timestamp)生成HMAC签名,服务端验证签名是否匹配且时间戳在合理范围内(防重放攻击)。
  • 限制访问IP:如果监听程序和服务端部署在同一台机器或固定内网IP,可以在Flask中配置只允许特定IP访问/api/notify_payment接口。

4.3 监控与日志

一个需要长期运行的系统,必须有完善的日志记录,以便出问题时排查。

  • 为Flask应用配置日志:可以使用Python标准库的logging模块,将日志输出到文件并按日期滚动。
  • 监听脚本同样需要记录日志,记录每次截图、识别结果、API调用情况。
  • 可以设置一个简单的健康检查端点,如GET /health,返回服务状态和最后活动时间。再配合一个外部的监控服务(如UptimeRobot)定期检查,确保服务在线。

4.4 应对微信客户端更新

UI自动化方案最大的风险来自于微信客户端的界面更新。如果微信改了聊天窗口的布局、字体颜色或消息气泡样式,我们的截图区域和OCR规则可能失效。

  • 策略1:区域动态检测:不要写死截图坐标,而是编写代码自动查找微信窗口,并基于窗口大小动态计算消息列表区域。
  • 策略2:特征匹配:使用OpenCV的模板匹配功能,在截图区域中寻找“收款”图标或特定颜色的消息气泡,再对这个气泡区域进行OCR,这样比全区域OCR更精准,对UI变化的容忍度也更高。
  • 策略3:人工确认兜底:对于无法识别的消息,可以将其截图保存到特定目录,并发出警报(如发送邮件),由人工后期处理。同时,系统应具备手动补单的功能。

5. 常见问题与排查技巧实录

在实际搭建和运行过程中,你几乎一定会遇到下面这些问题。这里记录了我的踩坑实录和解决方案。

5.1 OCR识别率低,金额或备注提取错误

这是最常见的问题。微信聊天窗口的背景、字体渲染、屏幕缩放都会影响。

  • 排查步骤1:检查截图质量。将capture_wechat_region函数截取的图片保存下来,用画图工具打开,看看是否清晰,文字有无模糊、断裂。
  • 排查步骤2:优化图像预处理。这是提升OCR精度的关键。尝试不同的预处理组合:
    def preprocess_for_ocr(img_cv): # 1. 转为灰度 gray = cv2.cvtColor(img_cv, cv2.COLOR_BGR2GRAY) # 2. 尝试自适应阈值,对光照不均更有效 binary = cv2.adaptiveThreshold(gray, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 11, 2) # 3. 可选的形态学操作:去除小噪点 kernel = np.ones((1,1), np.uint8) binary = cv2.morphologyEx(binary, cv2.MORPH_OPEN, kernel) # 4. 反转颜色(如果背景是深色) # binary = cv2.bitwise_not(binary) return binary
    多试几种方法,保存处理前后的图片对比,找到最适合你当前微信主题和屏幕的设置。
  • 排查步骤3:配置Tesseractpytesseract可以传递配置参数。对于中文数字混合,可以尝试:
    config = '--psm 6 -c tessedit_char_whitelist=0123456789.¥元备注:充值' text = pytesseract.image_to_string(processed_img, lang='chi_sim+eng', config=config)
    --psm 6假设文本为一块统一的区块,-c tessedit_char_whitelist限制只识别这些字符,能大幅提升准确率。
  • 终极方案:训练专属字体。如果项目非常重要,可以考虑收集一批微信收款截图,使用Tesseract的OCR训练工具,针对微信的字体进行微调训练,但这需要较多时间和精力。

5.2 监听程序运行一段时间后卡死或无响应

可能是内存泄漏、资源未释放,或者被Windows睡眠、锁屏打断。

  • 技巧1:定期重启。最简单粗暴但有效的方法。用任务计划程序设置监听脚本每天凌晨自动重启一次。
  • 技巧2:加入心跳和异常退出机制。在脚本主循环中,记录每次循环的时间。如果某次循环耗时异常长(比如超过60秒),则主动抛异常或重启自身。
    import sys def monitor_loop_with_watchdog(): last_loop_time = time.time() while True: loop_start = time.time() try: # ... 原有的监控逻辑 ... time.sleep(5) except Exception as e: print(f"循环出错,重启逻辑: {e}") # 可以在这里记录错误并发送警报 time.sleep(60) # 出错后等待久一点再继续 # 看门狗:如果单次循环超过60秒,可能卡住了,主动退出由外部进程重启 if time.time() - loop_start > 60: print("单次循环超时,主动退出") sys.exit(1)
  • 技巧3:防止锁屏干扰。确保运行监听程序的电脑电源设置中,关闭睡眠和关闭显示器的时间设为“从不”。也可以编写一个小脚本,定期模拟一次轻微的鼠标移动(如pyautogui.moveRel(0, 1))来防止系统进入休眠状态(注意不要影响正常使用)。

5.3 支付成功但系统未识别,或重复识别同一笔支付

  • 问题1:备注识别错误。用户可能没有严格按照提示填写备注,比如加了空格、换了标点。在服务端的正则匹配上要放宽规则,例如re.search(r'充值\s*(\w+)', note)可以匹配“充值 ABC123”或“充值ABC123”。
  • 问题2:去重逻辑有漏洞。上面提到的“分钟级指纹”在每分钟内有重复支付时会漏判。更好的方法是结合支付时间。微信消息中通常包含时间,如“下午2:15”。可以尝试用OCR识别这个时间,结合日期生成一个更精确的时间戳作为去重依据。如果识别时间困难,可以改为“金额+备注”作为键,但设置一个较长的过期时间(如30分钟),并记录到文件或数据库中,避免程序重启后丢失记录。
  • 问题3:网络问题导致回调失败。监听程序调用Flask接口时,可能因为网络波动失败。必须增加重试机制。
    import requests from requests.adapters import HTTPAdapter from urllib3.util.retry import Retry session = requests.Session() retries = Retry(total=3, backoff_factor=1, status_forcelist=[500, 502, 503, 504]) session.mount('http://', HTTPAdapter(max_retries=retries)) session.mount('https://', HTTPAdapter(max_retries=retries)) # 在调用时使用session try: resp = session.post(FLASK_NOTIFY_URL, json=payload, headers=headers, timeout=5) except requests.exceptions.RequestException as e: print(f"网络请求失败: {e}") # 可以将失败的任务存入一个本地队列或文件,稍后重试

5.4 如何应对微信多开或多个聊天窗口

如果同时登录了多个微信,或者需要监控多个聊天窗口(如文件传输助手和某个群聊),程序需要更智能。

  • 方案:枚举所有微信窗口。使用pygetwindow库获取所有标题包含“微信”的窗口,然后对每个窗口执行截图和识别。
    import pygetwindow as gw wechat_windows = [w for w in gw.getAllWindows() if '微信' in w.title] for win in wechat_windows: if win.isMinimized: win.restore() # 恢复窗口(可选,可能会打扰用户) # 获取窗口位置和大小 left, top, width, height = win.left, win.top, win.width, win.height # 对这个区域进行截图和识别... # 注意:识别后可能需要将窗口最小化回去
    但频繁切换和激活窗口会非常干扰用户。一个更友好的做法是:将需要监控的微信窗口单独放置在一个虚拟桌面或固定的屏幕位置,监听程序只监控这个特定区域,不影响主桌面的使用。

整个项目搭建下来,感觉更像是一个“系统集成”和“精细化调优”的工程。它没有用到多么高深的技术,但对稳定性、鲁棒性的要求极高。最大的体会是,在缺乏官方接口支持的情况下,利用现有工具链“拼凑”出一个可用的自动化方案,需要充分考虑各种边界情况和失败场景,日志和监控是你的最好朋友。这个方案虽然能跑通,但显然不适合高并发或对可靠性要求极高的生产环境,它更适用于个人项目、小范围测试或作为一种过渡方案。如果业务量增长,申请正式的商户支付接口仍然是唯一正途。