Skip to content

消息监听

pywxauto 提供基于事件驱动的消息监听机制,通过装饰器注册事件处理器,自动识别消息类型并分发。

基本用法

python
from pywxauto import Weixin, Event

wx = Weixin()

# 注册文本消息处理器
@wx.on(Event.TEXT)
def on_text(weixin, chat, message):
    print(f"{message.sender}: {message.content}")

# 注册要监听的会话(会打开为独立窗口)
wx.add_chat_listen(["张三", "工作群"])

# 启动监听(阻塞,Ctrl+C 退出)
wx.run()

事件类型

事件说明
Event.ALL所有消息
Event.TEXT文本消息
Event.IMAGE图片消息
Event.VIDEO视频消息
Event.FILE文件消息
Event.VOICE语音消息
Event.QUOTE引用消息
Event.EMOTION表情消息
Event.LOCATION位置消息
Event.LINK链接消息
Event.CARD卡片消息
Event.PERSONAL_CARD个人名片
Event.MERGE合并消息
Event.NOTE笔记消息
Event.VOIP通话消息
Event.RED_PACKET红包消息
Event.TRANSFER转账消息
Event.MUSIC音乐消息
Event.SYSTEM系统消息
Event.OTHER其他消息

监听多种消息类型

python
@wx.on([Event.TEXT, Event.IMAGE, Event.FILE])
def on_message(weixin, chat, message):
    print(f"[{message.type_label}] {message.sender}: {message.content}")

监听所有消息

python
@wx.on(Event.ALL)
def on_all(weixin, chat, message):
    print(message)

一次性监听

python
@wx.once(Event.TEXT)
def on_first_text(weixin, chat, message):
    print("收到第一条文本:", message.content)
    # 触发一次后自动移除

回调参数

所有回调函数的签名为:

python
def handler(weixin: Weixin, chat: SeparateChat, message: Message):
    ...
参数类型说明
weixinWeixin微信实例
chatSeparateChat消息来源的独立聊天窗口
messageMessage消息对象(具体子类)

在回调中回复

python
@wx.on(Event.TEXT)
def auto_reply(weixin, chat, message):
    if message.source.value == "others":
        chat.send_text(f"自动回复: 收到你的消息 [{message.content}]")

管理监听会话

python
# 添加监听
wx.add_chat_listen(["张三", "李四"])

# 自动发现所有已打开的独立窗口
wx.add_all_chats_listen()

# 移除监听
wx.remove_chat_listen(["张三"])

# 移除所有监听
wx.remove_all_chats_listen()

自动扫描新窗口

python
# auto_scan=True: 自动发现并监听新打开的独立聊天窗口
wx.run(auto_scan=True)

停止监听

python
import threading

# 从其他线程停止
def stop_after_10s():
    import time
    time.sleep(10)
    wx.stop()

threading.Thread(target=stop_after_10s, daemon=True).start()
wx.run()

移除事件处理器

python
# 移除特定处理器
wx.off(Event.TEXT, on_text)

# 移除某事件的所有处理器
wx.off(Event.TEXT)

# 移除所有处理器
wx.off()

轮询参数

python
wx.run(
    interval=0.1,       # 有新消息时的轮询间隔(秒)
    idle_interval=0.1,  # 无新消息时的轮询间隔(秒)
    auto_scan=False,    # 是否自动扫描新窗口
    listen_mode="ui",   # 监听模式: "ui"(UI 自动化)或 "db"(数据库监听)
)

数据库监听模式

除了默认的 UI 模式(通过独立聊天窗口监听),pywxauto 还支持数据库监听模式——直接监控微信的加密 SQLite 数据库文件,无需打开任何聊天窗口。

优势

  • 无需打开独立聊天窗口,自动监听所有会话
  • 不依赖窗口状态,更加稳定
  • 资源消耗低,通过 WAL 文件变化触发扫描

基本用法

python
from pywxauto import Weixin, Event

# 需要指定微信进程 PID
wx = Weixin(pid=12345)

@wx.on(Event.TEXT)
def on_text(weixin, chat, message):
    # 数据库模式下 chat 为 None
    # message 是一个字典
    print(f"{message['sender']}: {message['msg']}")

@wx.on(Event.ALL)
def on_all(weixin, chat, message):
    print(f"[{message['type']}] {message['from_wxid']} -> {message['to_wxid']}")

# 启动数据库监听
wx.run(listen_mode="db")

回调参数差异

数据库模式的回调签名与 UI 模式相同,但参数内容不同:

参数UI 模式DB 模式
weixinWeixin 实例Weixin 实例
chatSeparateChat 对象None
messageMessage 对象dict 字典

message 字典字段

字段类型说明
databasestr数据库文件名
tablestr消息表名
idint本地消息 ID(local_id)
msg_idint服务器消息 ID(server_id)
sequenceint排序序列号(sort_seq)
typeint消息类型(对应 DBEvent 枚举值)
is_senderint是否为自己发送(1=是, 0=否)
msgstr | dict消息内容(文本为 str,非文本消息解析为 dict)
sourcedict | None消息来源 XML 解析结果
at_user_listlist@用户列表
from_wxidstr | None发送者 wxid
senderstr | None发送者昵称
to_wxidstr | None接收者 wxid
receiverstr | None接收者昵称
room_wxidstr | None群聊 wxid(群消息时有值)
room_nicknamestr | None群聊昵称
extrabytes | None附加信息(packed_info_data)
statusint消息状态
create_timeint消息创建时间戳

DBEvent 枚举类型

数据库模式中 message['type'] 对应以下枚举值:

枚举值整数值说明映射到 Event
DBEvent.TEXT1文本消息Event.TEXT
DBEvent.TEXT22文本消息(变体)Event.TEXT
DBEvent.IMAGE3图片消息Event.IMAGE
DBEvent.VOICE34语音消息Event.VOICE
DBEvent.CARD42名片消息Event.CARD
DBEvent.VIDEO43视频消息Event.VIDEO
DBEvent.EMOTION47表情消息Event.EMOTION
DBEvent.LOCATION48位置消息Event.LOCATION
DBEvent.VOIP50通话消息Event.VOIP
DBEvent.OPEN_IM_CARD66企业名片Event.CARD
DBEvent.SYSTEM10000系统消息Event.SYSTEM
DBEvent.FILE25769803825文件消息Event.FILE
DBEvent.FILE_WAIT317827579953文件待接收Event.FILE
DBEvent.LINK21474836529链接消息Event.LINK
DBEvent.LINK2292057776177链接消息(变体)Event.LINK
DBEvent.SONG12884901937音乐消息Event.MUSIC
DBEvent.RED_ENVELOPE8594229559345红包消息Event.RED_PACKET
DBEvent.TRANSFER8589934592049转账消息Event.TRANSFER
DBEvent.QUOTE244813135921引用消息Event.QUOTE
DBEvent.MERGED_FORWARD81604378673合并转发Event.MERGE
DBEvent.FINDER_VIDEO219043332145视频号视频Event.OTHER
DBEvent.COLLECTION103079215153收藏消息Event.OTHER
DBEvent.PAT266287972401拍一拍Event.OTHER
DBEvent.GROUP_ANNOUNCEMENT373662154801群公告Event.SYSTEM

完整示例

python
from pywxauto import Weixin, Event

wx = Weixin(pid=12345)

@wx.on(Event.TEXT)
def on_text(weixin, chat, message):
    sender = message["sender"]
    content = message["msg"]
    room = message.get("room_nickname")
    if room:
        print(f"[{room}] {sender}: {content}")
    else:
        print(f"{sender}: {content}")

@wx.on(Event.IMAGE)
def on_image(weixin, chat, message):
    print(f"收到图片消息来自: {message['sender']}")

@wx.on(Event.FILE)
def on_file(weixin, chat, message):
    print(f"收到文件消息来自: {message['sender']}")

@wx.on(Event.ALL)
def on_all(weixin, chat, message):
    print(f"[{message['database']}/{message['table']}] "
          f"type={message['type']} "
          f"{message['from_wxid']} -> {message['to_wxid'] or message['room_wxid']}")

wx.run(listen_mode="db")

注意事项

  • 需要指定 pid 参数(用于读取进程内存获取数据库密钥)
  • 需要管理员权限运行(读取进程内存)
  • 依赖 pymemsqlcipher3zstandardxmltodict(已包含在安装依赖中)
  • 微信进程需要运行中且已登录
  • 该模式不支持发送消息,仅用于接收和处理消息
  • 非文本消息的 msg 字段会被自动解析为 XML 字典

WeixinManager 多实例数据库监听

使用 WeixinManager 可以同时监听多个微信客户端的数据库:

python
from pywxauto import WeixinManager, Event

wx = WeixinManager()

@wx.on(Event.TEXT)
def on_text(weixin, chat, message):
    print(f"[PID={weixin.pid}] {message['sender']}: {message['msg']}")

@wx.on(Event.ALL)
def on_all(weixin, chat, message):
    print(f"[PID={weixin.pid}] [{message['type']}] {message['from_wxid']}")

# 所有已连接客户端同时启动数据库监听
wx.run(listen_mode="db")

完整示例:智能机器人

python
from pywxauto import Weixin, Event

wx = Weixin(background=True)

@wx.on(Event.TEXT)
def on_text(weixin, chat, message):
    if message.source.value != "others":
        return
    content = message.content.strip()
    if content == "你好":
        chat.send_text("你好!有什么可以帮你的?")
    elif content == "时间":
        import datetime
        chat.send_text(f"现在是 {datetime.datetime.now().strftime('%H:%M:%S')}")

@wx.on(Event.IMAGE)
def on_image(weixin, chat, message):
    if message.source.value != "others":
        return
    chat.send_text("收到图片!")

@wx.on(Event.FILE)
def on_file(weixin, chat, message):
    if message.source.value != "others":
        return
    chat.send_text(f"收到文件: {message.file_name} ({message.file_size})")

wx.add_chat_listen(["文件传输助手"])
wx.run()