这是一个非常经典和实用的组合,可以让你:

- 通过 Flask 搭建一个网站或 API 接口。
- 通过 WxPy 运行一个微信机器人,实现自动回复、好友管理、群管理等功能。
- 让这两者能够互相通信,通过 Web 网页发送指令给微信机器人,或者让微信机器人将收到的消息推送到 Web 页面上显示。
核心概念与工作流程
- Python: 作为基础编程语言,连接所有组件。
- Flask: 一个轻量级的 Web 框架,它会启动一个 Web 服务器,监听来自浏览器的 HTTP 请求(比如用户点击按钮、提交表单),并根据请求返回响应(HTML 页面或 JSON 数据)。
- WxPy: 一个强大的微信个人号接口库,它会登录你的微信,并持续监听来自微信的消息(好友消息、群消息、好友请求等)。
它们如何协同工作?
最核心的挑战在于,Flask 的 Web 服务器是事件驱动、阻塞式的(在处理一个请求时,不能处理其他请求),而 WxPy 的机器人是长期运行、轮询式的(需要一直在线等待消息),如果直接在同一个主线程中运行,Flask 将无法响应任何 Web 请求,因为线程会被 WxPy 的 embed() 方法阻塞。
我们必须使用多线程来解决这个问题。
标准工作流程:

- 主线程:启动 Flask 应用。
- 子线程 1:运行 WxPy 机器人的
bot.embed(),让它保持登录并监听微信消息。 - 子线程 2 (可选):运行一个简单的 Flask 开发服务器,或者由主线程来启动它。
当有微信消息到达时,WxPy 的回调函数(如 @bot.register)会被触发,在这个回调函数中,我们可以执行任何操作,
- 调用一个 Flask 的 API 端点(通过
requests库)。 - 修改一个共享的变量(需要使用线程安全的方式,如
queue.Queue)。 - 直接操作一个由 Flask 提供的数据库。
当有 Web 请求到达时,Flask 的视图函数会被触发,在这个函数中,我们可以:
- 调用 WxPy 的 API(如
bot.file_helper.send_file())来发送文件。 - 读取由 WxPy 线程更新的共享变量,并将数据显示在网页上。
环境准备
确保你已经安装了必要的库。
# 安装 Flask pip install Flask # 安装 WxPy (注意:WxPy 已停止维护,但仍然可用) # 推荐使用 `wxpy`,它是一个较新的 fork pip install wxpy # (可选) 如果需要在 Flask 视图函数中调用 WxPy API,确保它们在同一进程 # 如果分开,则需要用 HTTP 请求通信 pip install requests
实战案例:一个简单的 Web 控制台
这个案例将实现以下功能:

- 微信机器人自动回复所有好友消息。
- 启动一个 Flask 网站,网站上有两个按钮:
- "发送文件": 点击后,机器人会通过文件传输助手发送一个指定的文本文件。
- "获取好友列表": 点击后,页面会显示机器人的前 10 个好友。
第 1 步:编写微信机器人代码 (robot.py)
这个脚本将负责登录微信和定义消息回复逻辑。
# robot.py
from wxpy import Bot, Message
import threading
import time
# 全局变量,用于存储好友列表,以便 Flask 读取
# 注意:直接共享全局变量在多线程中可能不安全,这里为了简化演示。
# 在生产环境中,建议使用 queue.Queue 或数据库。
global_friends_cache = []
def wechat_bot_logic():
"""
WxPy 机器人的核心逻辑,将在子线程中运行。
"""
print("正在登录微信...")
# cache_path=True 可以缓存登录状态,下次不用扫码
bot = Bot(cache_path=True)
print("登录成功!")
# 注册消息回调函数,自动回复所有文本消息
@bot.register(Message, TEXT)
def auto_reply(msg):
print(f"收到来自 {msg.sender} 的消息: {msg.text}")
# 回复消息
msg.reply(f"我已经收到你的消息: {msg.text}")
# 可以在这里调用 Flask API,
# requests.post('http://127.0.0.1:5000/api/received_message', json={'sender': msg.sender.name, 'content': msg.text})
# 更新全局好友列表
global global_friends_cache
global_friends_cache = bot.friends(update=True)[:10] # 只取前10个
print("已更新好友列表缓存。")
# 嵌入微信的终端,保持机器人运行
print("机器人已启动,等待消息...")
bot.embed() # 这会阻塞当前线程
if __name__ == '__main__':
# 启动机器人线程
bot_thread = threading.Thread(target=wechat_bot_logic, daemon=True)
bot_thread.start()
# 主线程可以继续做其他事情,比如启动 Flask
# 或者就保持运行
while True:
time.sleep(1)
第 2 步:编写 Flask Web 应用 (app.py)
这个脚本将创建 Web 服务器和用户界面。
# app.py
from flask import Flask, render_template_string, request
import requests # 用于调用 WxPy 的 API (WxPy 在另一个进程中)
# --- 注意 ---
# 在这个例子中,我们将 WxPy 和 Flask 放在同一个进程中。
# 这样,Flask 的视图函数可以直接访问 `bot` 对象。
# 但请注意,这仍然需要将 WxPy 的 `embed()` 放在单独的线程中。
from wxpy import Bot
import threading
# 创建 Flask 应用
app = Flask(__name__)
# 全局变量,用于存储 bot 实例
# 注意:直接在 Flask 视图中使用全局 bot 对象,前提是它已经在另一个线程中被初始化。
# 这是一种比较简单但不完全线程安全的方式。
global_bot = None
# HTML 模板
HTML_TEMPLATE = """
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">微信机器人控制台</title>
<style>
body { font-family: sans-serif; margin: 40px; }
h1 { color: #333; }
.container { max-width: 600px; margin: auto; padding: 20px; border: 1px solid #ccc; border-radius: 8px; }
button { padding: 10px 15px; margin: 10px 5px; font-size: 16px; cursor: pointer; }
button:hover { background-color: #f0f0f0; }
#friend-list { margin-top: 20px; border: 1px solid #eee; padding: 10px; border-radius: 5px; }
.friend-item { padding: 5px 0; border-bottom: 1px solid #eee; }
</style>
</head>
<body>
<div class="container">
<h1>微信机器人控制台</h1>
<p>这是一个由 Flask 和 WxPy 驱动的简单控制台。</p>
<h2>机器人操作</h2>
<button onclick="sendFile()">发送文件到文件传输助手</button>
<button onclick="getFriends()">获取好友列表</button>
<div id="friend-list"></div>
</div>
<script>
function sendFile() {
alert('正在发送文件...');
fetch('/send_file')
.then(response => response.json())
.then(data => alert(data.message));
}
function getFriends() {
alert('正在获取好友列表...');
fetch('/get_friends')
.then(response => response.json())
.then(data => {
const listDiv = document.getElementById('friend-list');
if (data.friends.length > 0) {
listDiv.innerHTML = '<h3>好友列表:</h3>';
data.friends.forEach(friend => {
listDiv.innerHTML += `<div class="friend-item">- ${friend.name} (ID: ${friend.id})</div>`;
});
} else {
listDiv.innerHTML = '<p>未能获取到好友列表。</p>';
}
});
}
</script>
</body>
</html>
"""
def run_bot():
"""
在子线程中初始化并运行 WxPy 机器人。
"""
global global_bot
print("机器人线程启动...")
global_bot = Bot(cache_path=True)
print("机器人登录成功。")
# 可以在这里添加机器人的其他逻辑,比如自动回复
from wxpy import Message, TEXT
@global_bot.register(Message, TEXT)
def reply(msg):
msg.reply(f"Web控制台已收到: {msg.text}")
global_bot.embed() # 阻塞机器人线程
# 启动机器人线程
bot_thread = threading.Thread(target=run_bot, daemon=True)
bot_thread.start()
# 等待 bot 初始化完成
import time
time.sleep(3) # 给 bot 几秒钟时间来登录
# Flask 路由
@app.route('/')
def index():
return render_template_string(HTML_TEMPLATE)
@app.route('/send_file')
def send_file_route():
"""
通过 Web 请求,让机器人发送一个文件。
"""
if global_bot:
try:
# 创建一个简单的文本文件并发送
content = "这是从 Web 控制台发送的文件!\n时间: " + str(time.time())
with open('test_from_web.txt', 'w', encoding='utf-8') as f:
f.write(content)
global_bot.file_helper.send_file('test_from_web.txt')
return {'message': '文件发送成功!'}
except Exception as e:
return {'message': f'发送失败: {str(e)}'}
return {'message': '机器人未初始化'}
@app.route('/get_friends')
def get_friends_route():
"""
通过 Web 请求,获取机器人好友列表。
"""
if global_bot:
try:
friends = global_bot.friends()
# 返回 JSON 格式的好友信息
return {'friends': [{'name': f.name, 'id': f.id} for f in friends[:10]]}
except Exception as e:
return {'message': f'获取好友列表失败: {str(e)}', 'friends': []}
return {'message': '机器人未初始化', 'friends': []}
if __name__ == '__main__':
# 运行 Flask 应用
# host='0.0.0.0' 允许从网络中的其他计算机访问
app.run(debug=True, port=5000, host='0.0.0.0')
第 3 步:运行应用
- 保存文件:将上面的代码分别保存为
robot.py和app.py。 - 运行 Flask 应用:在终端中,进入文件所在目录,运行
app.py。python app.py
- 扫码登录:程序会弹出一个二维码,使用你的微信扫描二维码登录。
- 访问网站:登录成功后,打开浏览器访问
http://127.0.0.1:5000。 - 测试功能:
- 在微信上给你的机器人发消息,它会自动回复。
- 在网页上点击“发送文件”按钮,你的微信文件传输助手会收到一个
test_from_web.txt文件。 - 点击“获取好友列表”按钮,页面会显示你的部分好友信息。
高级架构与最佳实践
上面的例子为了简单,将 bot 对象作为全局变量,对于更复杂的应用,这种做法并不健壮,以下是更推荐的架构:
进程间通信 (IPC)
这是最健壮、最灵活的架构,特别适合大型或分布式应用。
- Flask 进程:只负责 Web 服务,不包含任何 WxPy 代码,它暴露 API 端点。
- WxPy 进程:只负责与微信交互,它监听微信消息,并通过某种方式通知 Flask 进程。
- 通信桥梁:两者之间通过一个中间件进行通信。
通信桥梁的选择:
-
消息队列:如 Redis、RabbitMQ、Celery。
- WxPy 进程:收到消息后,将消息数据(发送者、内容、时间等)作为任务推送到队列中。
- Flask 进程:有一个后台任务(如 Celery Worker)从队列中取出任务,进行处理(例如存入数据库、触发 Webhook)。
- 优点:解耦度高,性能好,支持异步。
- 缺点:架构更复杂,需要额外的服务。
-
HTTP API:
- WxPy 进程:收到消息后,使用
requests库向 Flask 的一个特定 API 端点(如/api/wehook)发送一个 POST 请求。 - Flask 进程:接收这个请求,处理数据。
- 优点:实现简单,易于理解。
- 缺点:耦合度稍高,WxPy 进程需要知道 Flask 的地址。
- WxPy 进程:收到消息后,使用
共享数据库
这是另一种常见的解耦方式。
- WxPy 进程:收到消息后,将消息内容写入一个共享的数据库(如 SQLite, MySQL, PostgreSQL)。
- Flask 进程:通过查询数据库来获取最新的消息,并展示在 Web 页面上,Flask 也通过写入数据库来向 WxPy 发送指令(创建一个“待发送消息”的表)。
- WxPy 进程:可以定期轮询“待发送消息”表,发现有新指令就执行。
优点:数据持久化,架构清晰。 缺点:存在一定的延迟(轮询或查询开销),需要处理数据库并发问题。
| 特性 | 简单多线程 (直接调用) | 进程间通信 (如 HTTP API) | 共享数据库 |
|---|---|---|---|
| 复杂度 | 低 | 中 | 中 |
| 耦合度 | 高 | 低 | 中 |
| 性能 | 一般 | 高 | 取决于数据库和查询 |
| 健壮性 | 低 (一个崩溃可能影响另一个) | 高 (进程隔离) | 高 (数据持久化) |
| 适用场景 | 快速原型、小型工具 | 大多数生产环境、需要解耦的场景 | 需要数据持久化、有复杂业务逻辑的场景 |
对于初学者,从简单多线程开始是最好的选择,当你需要构建更稳定、可扩展的应用时,应该转向进程间通信或共享数据库的架构。
