V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐学习书目
Learn Python the Hard Way
Python Sites
PyPI - Python Package Index
http://diveintopython.org/toc/index.html
Pocoo
值得关注的项目
PyPy
Celery
Jinja2
Read the Docs
gevent
pyenv
virtualenv
Stackless Python
Beautiful Soup
结巴中文分词
Green Unicorn
Sentry
Shovel
Pyflakes
pytest
Python 编程
pep8 Checker
Styles
PEP 8
Google Python Style Guide
Code Style from The Hitchhiker's Guide
pytth
V2EX  ›  Python

Python 实现 Windows 微信消息通知(可显示发送人和消息内容)

  •  
  •   pytth · 2022-08-29 10:06:44 +08:00 · 4601 次点击
    这是一个创建于 819 天前的主题,其中的信息可能已经有所发展或是发生改变。

    需求

    Mac 微信是有一个消息通知的,这一点就挺好的,有时候根本不用点开开看就能看到消息内容。而 Windows 电脑版是没有这个消息通知的,只有右下角图标闪烁。

    于是我想了不少的办法去实现这么一个功能,已经另辟蹊径实现了这个功能,其实也有一定的局限性,但是能满足办公期间的小需求。

    效果如下:

    实现方法

    接收通知

    首先是 Windows 的通知弹出的实现就是 Windows 自带的通知栏,我们可以通过 Python 去调用 Windows API 去发送 Windows 通知,让消息弹出来。

    发送通知

    相比于接收通知,那么发送通知就比较困难,因为 Windows 微信电脑版的窗口属于非 Windows 窗口标准,我们无法通过常规的方式去读取每个控件的内容,更无法监听到通知内容,所以我这边另辟蹊径,通过安卓手机去监听微信消息。

    所以这里用到了 SmsForwarder 这款开源软件,安装在你的安卓手机上,然后设置转发规则,监听微信 APP 的通知,然后发送通道选择 WebHook ,将监听到的消息 POST 到 Python 开启的 HTTP 服务器,触发 Windows 通知就行了!

    上代码

    toasts.py

    from flask import Flask, request
    from winotify import Notification
    import urllib.parse
    import win32gui
    import win32con
    
    app = Flask(__name__)
    
    @app.route('/')  # 获取 url 信息
    def getUrlInfo():
        # 完整 url
        url = request.url
        # 主机部分
        hostUrl = request.host_url
        # 访问路径
        fullPath = request.full_path
        # 输出
        print('收到推送任务,推送内容是:'+str(urllib.parse.unquote(fullPath.split("/?")[1])).replace('+', ' ', 1))
    
        # 接收到的内容
        content = str(urllib.parse.unquote(fullPath.split("/?")[1])).replace('+', ' ', 1);
    
        # 错误处理
        # 因为监听软件那边监听到的首条消息是没有带上微信用户昵称的
        # 所以需要判断当前接收到的消息是不是首条消息
        # 如果不做这一步就会出错
    
        pdmh = ":" in content
        if pdmh == True:
            # 截取:前面的内容
            qianmian = content.split(":")[0]
            weixinMsg = content.split(":")[1]
            # 还要将[]这一块也去掉,这就提取到了微信昵称
            nickname = qianmian.split("]")[1]
        else:
            nickname = '微信消息通知'
            weixinMsg = content
    
        # 开发 Push 通知
        # toaster = ToastNotifier()
        # toaster.show_toast(title=nickname, msg=weixinMsg,icon_path="logo.ico", duration=5)
        toast = Notification(app_id="通知中心",title=nickname,msg=weixinMsg,icon=r"D:\Python\demo\wechat.png")
        toast.show()
        return "ok"
    
    
    def notify(hwnd, msg, wparam, lparam):
        print("notify", msg)
        if lparam == win32con.WM_LBUTTONDBLCLK:  # 双击左键
            print("双击左键", msg)
            pass
        elif lparam == win32con.WM_RBUTTONUP:  # 右键弹起
            print("右键弹起", msg)
            pass
        elif lparam == win32con.WM_LBUTTONUP:  # 左键弹起
            print("左键弹起", msg)
            pass
        return True
    
    wc = win32gui.WNDCLASS()
    wc.hInstance = win32gui.GetModuleHandle(None)
    wc.lpszClassName = "Windows 通知中心"
    wc.style = win32con.CS_VREDRAW | win32con.CS_HREDRAW;
    wc.lpfnWndProc = notify
    classAtom = win32gui.RegisterClass(wc) 
    hwnd =win32gui.CreateWindow(classAtom,"tst2",win32con.WS_OVERLAPPEDWINDOW,win32con.CW_USEDEFAULT,win32con.CW_USEDEFAULT,win32con.CW_USEDEFAULT,win32con.CW_USEDEFAULT,None,None,None,None)
    notify_id = (hwnd,0,win32gui.NIF_ICON | win32gui.NIF_MESSAGE | win32gui.NIF_TIP,win32con.WM_USER + 20,win32gui.LoadIcon(0, win32con.IDI_APPLICATION),"Windows 通知中心")
    win32gui.Shell_NotifyIcon(0,notify_id)
    
    # 在指定 IP 和端口开启 HTTP 服务
    if __name__ == '__main__':
        app.run(debug=False,host='192.168.1.100', port=8080)
    

    代码说明

    192.168.1.100 是我电脑的内网 ip ,8080 是端口号,你需要获取你电脑的内网 ip 换上去,不然后续配置安卓那边的监听转发端就无法正常转发通知。

    执行代码后,会在你电脑开启一个 HTTP 服务,这时候你可以在浏览器进行本地测试,在浏览器按照以下格式粘贴:

    http://内网 ip:端口号 /?通知内容
    

    安卓手机配置

    安装 SmsForwarder 这款软件。

    下载地址: https://gitee.com/pp/SmsForwarder/releases/tag/v3.0.8

    设置发送通道,选择 Webhook ,Webserver 按照以下格式填写:

    http://内网 ip:端口号 /
    

    WebParams 直接填写 [msg] ,请求方式是 GET

    设置转发规则,添加规则,选择匹配 “APP 包名”,匹配模式选择 “是”,匹配值是 com.tencent.mm ,选择刚才配置的发送通道,自定义模板直接点击通知内容。

    简单进行配置后,SmsForwarder 进行一些必要的设置后,就可以正常使用了。

    需要优化的地方

    目前还在想办法在电脑本地监听微信消息,毕竟通过安卓手机监听消息也不是办法,一方面是依赖本地的服务器,通过局域网才可以发送通知给电脑。另一方面就是安卓监听消息也不具备稳定性,而且也不是人人都用安卓,对于苹果手机的用户,也是难以实现这个。

    需要注意的地方

    1. 内网 ip 可能会变化,如果你发现后面无法正常接收到通知,可以检查下内网 ip ,更换一下 ip 重启服务。

    2. 因为这是使用内网 ip 实现的 HTTP 服务,所以你安卓手机需要连接的 wifi 与电脑的一致,如果电脑是有线网络,那么你手机需要与电脑有线网络同一个网络环境,即 ip 相同。

    3. 如果不想通过局域网实现,可以自己配置内网穿透服务去实现外网请求服务。

    监听微信消息的方案

    1. 自写 Hook 微信,读取内存去监听微信消息

    2. 使用现成的方案,市面上也有一些 Hook 微信的框架,例如可爱猫,这个框架提供了非常便利的 SDK 去调用 API 来监听微信聊天消息,甚至还可以做到发送消息。

    19 条回复    2022-12-04 19:20:12 +08:00
    ysc3839
        1
    ysc3839  
       2022-08-29 12:21:53 +08:00
    > 因为 Windows 微信电脑版的窗口属于非 Windows 窗口标准,我们无法通过常规的方式去读取每个控件的内容,更无法监听到通知内容
    实测可以使用无障碍接口获取,微信是支持的。可以用 Windows SDK 附带的 inspect.exe 试试看。
    brucmao
        2
    brucmao  
       2022-08-29 14:11:00 +08:00
    昨天看到一个 sublime text 通知插件,挺好玩的
    http://facelessuser.github.io/SubNotify/
    PRStarDust
        3
    PRStarDust  
       2022-08-29 15:06:05 +08:00
    话说你们不会觉得 Windows 的通知中心很难用吗?这个右下角的通知每次弹出来,既不能像安卓那样划掉,又不能点击那个 X 来彻底关掉,点 X 只是消除他的悬浮显示,并不能让它从通知中心彻底消失,所以我只好把所有应用的通知权限关掉...
    pytth
        4
    pytth  
    OP
       2022-08-29 15:10:05 +08:00
    是的,要进入通知中心列表再次 X 掉
    @PRStarDust
    icepie
        5
    icepie  
       2022-08-29 21:09:54 +08:00
    貌似装个 kde connect 就解决了你的需求
    01046
        6
    01046  
       2022-08-30 00:16:00 +08:00
    对呀,kde connect 就可以了啊。。。
    话说 kde connect 什么时候可以修复手机剪贴板同步到 PC 无效的 BUG 啊,现在用 join ,感觉不是很稳定
    RyanLin1995
        7
    RyanLin1995  
       2022-08-30 10:37:42 +08:00
    我没记错的话,win11 好像已经实现了
    pytth
        8
    pytth  
    OP
       2022-08-30 11:02:46 +08:00
    @icepie
    @01046

    感谢推荐,我试了一下,确实是不错,这个软件还可以获取到微信头像!
    pytth
        9
    pytth  
    OP
       2022-08-30 11:03:21 +08:00
    @RyanLin1995 win11 也没有像 mac 一样弹出微信消息通知。
    pytth
        10
    pytth  
    OP
       2022-08-30 11:04:50 +08:00
    @ysc3839 感谢提醒,我用 ui spy.exe 试了下,之前试了一下是不行的,重新研究了,确实是可以得到每个控件,连每条聊天记录都可以获取到!感觉可以开发很多微信的小工具出来。
    icepie
        11
    icepie  
       2022-08-30 11:18:39 +08:00
    其实我也挺困扰的...为什么微信 pc 端不调用系统的通知 api...
    kid740246048
        12
    kid740246048  
       2022-08-30 12:18:15 +08:00 via Android
    @01046 Android 10 之后不允许后台读取剪贴板,可以装个 magisk 模块来绕过
    RyanLin1995
        13
    RyanLin1995  
       2022-08-30 16:40:27 +08:00
    @pytth 我记得我的预览版 win11 是有的,等我今晚回去确定一下
    01046
        14
    01046  
       2022-08-31 02:12:51 +08:00
    @kid740246048 谢谢,请教一下模块名字? 剪贴板互通是刚需
    kid740246048
        15
    kid740246048  
       2022-08-31 02:15:20 +08:00
    01046
        16
    01046  
       2022-08-31 02:44:46 +08:00
    啊,没事了,用关键词搜到了,clipboard whitelist
    01046
        17
    01046  
       2022-08-31 02:45:16 +08:00
    原来已经被回复了,还是非常感谢
    llsquaer
        18
    llsquaer  
       2022-09-01 18:58:57 +08:00
    思路很不错..我觉得直接自己写一个弹窗比 windows 自带的好用多了
    cx1251cx
        19
    cx1251cx  
       2022-12-04 19:20:12 +08:00
    我只能说,你们玩 it 的……是真牛逼啊
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   6042 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 26ms · UTC 02:47 · PVG 10:47 · LAX 18:47 · JFK 21:47
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.