Automatisation de l'envoi de messages WeChat via une API Flask

Cette approche consiste à exposer un service HTTP local avec Flask qui pilote le client WeChat pour Windows à l'aide de la bibliothèque wxauto. Il n'est pas nécessarie d'intercepter ou de déchiffrer le protocole WeChat, ce qui réduit les risques liés à la sécurité du compte.

Prérequis

  • Windows 10/11 avec WeChat pour PC ouvert et une session active.
  • Python 3 installé.

Instalaltion des dépendances

pip install wxauto flask pywin32

Fontcionnement

Le serveur repère le handle de la fenêtre WeChat, initialise un objet WeChat, puis expose deux points d'entrée HTTP POST pour envoyer un message texte ou un fichier à un contact ou un groupe donné.

Script serveur

from wxauto import WeChat
import win32gui
import os
from pathlib import Path
from flask import Flask, request, jsonify
from werkzeug.utils import secure_filename


def locate_wechat_handle():
    candidates = ["WeChatMainWndForPC", "WeChatMainWndForStore"]
    for class_name in candidates:
        hwnd = win32gui.FindWindow(class_name, None)
        if hwnd:
            print(f"Fenêtre WeChat détectée : handle={hwnd}")
            return hwnd
    print("Client WeChat introuvable.")
    return None


hwnd = locate_wechat_handle()
if not hwnd:
    raise RuntimeError("Veuillez lancer WeChat avant de démarrer le service.")


client = WeChat()
app = Flask(__name__)


@app.route('/api/message', methods=['POST'])
def post_message():
    if 'recipient' not in request.form:
        return jsonify({'error': 'Destinataire absent'}), 400
    if 'content' not in request.form:
        return jsonify({'error': 'Contenu absent'}), 400

    recipient = request.form['recipient']
    content = request.form['content']

    try:
        client.SendMsg(msg=content, who=recipient)
        return jsonify({'status': 'ok'}), 200
    except Exception as exc:
        return jsonify({
            'error': 'Échec de l\'envoi du message',
            'details': str(exc)
        }), 500


@app.route('/api/file', methods=['POST'])
def post_file():
    if 'file' not in request.files:
        return jsonify({'error': 'Fichier absent'}), 400
    if 'recipient' not in request.form:
        return jsonify({'error': 'Destinataire absent'}), 400

    recipient = request.form['recipient']
    upload = request.files['file']
    path = persist_upload(upload)

    if not path:
        return jsonify({'error': 'Stockage du fichier impossible'}), 500

    try:
        client.SendFiles(filepath=path, who=recipient)
        return jsonify({'status': 'ok'}), 200
    except Exception as exc:
        if os.path.exists(path):
            os.remove(path)
        return jsonify({
            'error': 'Échec de l\'envoi du fichier',
            'details': str(exc)
        }), 500


def persist_upload(upload):
    if not upload or not upload.filename:
        return None

    folder = Path('uploads')
    folder.mkdir(exist_ok=True)

    filename = secure_filename(upload.filename)
    destination = folder / filename
    upload.save(destination)
    return str(destination)


if __name__ == '__main__':
    app.run(host='0.0.0.0', port=80)

Script client

import requests


def notify(recipient, content):
    endpoint = "http://127.0.0.1/api/message"
    payload = {"recipient": recipient, "content": content}

    try:
        response = requests.post(endpoint, data=payload, timeout=10)
        if response.status_code == 200:
            print("Message envoyé :", response.json())
        else:
            print(f"Erreur {response.status_code} : {response.text}")
    except requests.RequestException as exc:
        print(f"Erreur réseau : {exc}")


if __name__ == '__main__':
    notify("Nom du contact ou du groupe", "Contenu du message")

Le point d'entrée texte attend les champs recipient et content. Le point d'entrée fichier attend un champ file en multipart/form-data et un champ recipient.

Étiquettes: wxauto Flask WeChat win32gui Windows

Publié le 9 juillet à 03h32