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.