python使用win32和flask實現接收請求發送QQ消息

1.說明:
這是一個很奇怪的需求:獲取手機短信(篩選),讀取並且調用http請求,程序自動實現將短信內容發送到對應qq窗口;
這邊讀取手機短信併發送請求是用h5+寫的一個app,後臺用python寫一個帶界面的web服務器。

2.具體流程:
啓動後臺exe,先檢測對應qq窗口是否存在(窗口需要單獨拎出來不然無法獲取句柄),顯示本機ip(服務器ip),點擊啓動就會啓動服務器,然後手機填寫該地址,每次收到短信就會發送請求到本機服務器(只支持內網,也就是手機要連接內部的無線網)。
在這裏插入圖片描述
3.代碼實現

import flask
import socket
import json
import win32clipboard
import win32gui
import win32con
import tkinter
import _thread
import time
import re
import sys
import logging
import os


server = flask.Flask(__name__)  # 創建1個Flask實例
ui_title = "智恆達自動發送程序"
qq_group_1 = "***羣"
qq_group_2 = "####羣"
reg1 = re.compile(r'(.*)銀行(.*)520520') 
reg2 = re.compile(r'(.*)銀行(.*)748748')
# 處理日誌,每次啓動都會刷新
if not os.path.isdir(r'E:\py_log'):
    os.makedirs(r'E:\py_log')
logging.basicConfig(filename='E:\py_log\pyexe.log', filemode="w", level=logging.INFO)


# sendmsg接口
@server.route('/qq/sendmsg', methods=['post'])
def sendmsg_2_qq():
    logging.info(">>>")
    now = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
    logging.info(f">>>{now}")
    msginfo = flask.request.get_data()  # 前臺application/json
    msgcontent = json.loads(msginfo).get('msginfo')
    logging.info(f">>>接收到的消息爲:{msgcontent}")
    if msginfo is None:
        msgcontent = "空"
    if reg1.match(msgcontent) is not None:
        result = send_msg(msgcontent, qq_group_1)
    elif reg2.match(msgcontent) is not None:
        result = send_msg(msgcontent, qq_group_2)
    else:
        result = "短信內容不匹配,無法發送"
    # 處理結果
    res = {
        'msg': None,
        'msg_code': None}
    if result == "":
        res['msg'] = "處理成功"
        res['msg_code'] = 0
    else:
        res['msg'] = result
        res['msg_code'] = 1
    logging.info(f">>>{res}")
    return json.dumps(res, ensure_ascii=False)


# 獲取本機ip
def get_host_ip():
    sok = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    try:
        sok.connect(('8.8.8.8', 80))
        ip = sok.getsockname()[0]
    finally:
        sok.close()
    return ip


# 獲取窗口併發送消息 0成功 1失敗
def send_msg(sendmsg, winname):
    qqhd = win32gui.FindWindow("TXGuiFoundation", winname)
    rt_msg = ""
    if qqhd == 0:
        rt_msg = f"找不到{winname}窗口,無法發送"
    else:
        try:
            if win32gui.IsIconic(qqhd):
                logging.info(">>>窗口已經最小化了")
                win32gui.ShowWindow(qqhd, win32con.SW_SHOWNORMAL)
                time.sleep(0.1)
            logging.info(">>>開始虛擬按鍵操作")
            # 設置剪貼板
            win32clipboard.OpenClipboard()
            win32clipboard.EmptyClipboard()
            win32clipboard.SetClipboardData(win32con.CF_UNICODETEXT, sendmsg)
            win32clipboard.CloseClipboard()
            time.sleep(0.1)
            # 填充消息
            win32gui.PostMessage(qqhd, win32con.WM_CHAR, 22, 2080193)
            win32gui.PostMessage(qqhd, win32con.WM_PASTE, 0, 0)
            time.sleep(0.1)
            # 回車發送消息
            win32gui.PostMessage(qqhd, win32con.WM_KEYDOWN, win32con.VK_RETURN, 0)
            win32gui.PostMessage(qqhd, win32con.WM_KEYUP, win32con.VK_RETURN, 0)
            time.sleep(0.1)
            # 清空剪貼板
            win32clipboard.OpenClipboard()
            win32clipboard.EmptyClipboard()
            win32clipboard.CloseClipboard()
            time.sleep(0.5)
        except Exception as e:
            logging.info(f">>>出現異常:{e}")
            rt_msg = "程序異常"
    return rt_msg


# 校驗
def check_wins():
    gp1hd = win32gui.FindWindow("TXGuiFoundation", qq_group_1)
    if gp1hd == 0:
        raise Exception(f"找不到{qq_group_1}窗口,無法啓動")
    else:
        logging.info(f">>>>已找到{qq_group_1}窗口")
    gp2hd = win32gui.FindWindow("TXGuiFoundation", qq_group_2)
    if gp2hd == 0:
        raise Exception(f"找不到{qq_group_2}窗口,無法啓動")
    else:
        logging.info(f">>>>已找到{qq_group_2}窗口")
    return 1


# 關閉tk窗口
def close_tk():
    tkhd = win32gui.FindWindow("TkTopLevel", ui_title)
    if tkhd == 0:
        raise Exception("找不到tk窗口,無法關閉")
        # 最小化
    win32gui.CloseWindow(tkhd)


# 啓動flask服務器接收請求
def start_server():
    server.run(port=8008, host=get_host_ip(), threaded=False)


# 另開一個線程啓動服務器
def create_thread(start_button):
    _thread.start_new_thread(start_server, ())
    time.sleep(1)
    start_button.config(state='disabled')
    close_exewin()
    close_tk()


# 關閉cmd.exe窗口,不存在也不會報錯
def close_exewin():
    exename = str(sys.executable)
    logging.info(f">>>httpservice.exe窗口路徑爲:{exename}")
    exehd = win32gui.FindWindow("ConsoleWindowClass", exename)
    if exehd == 0:
        logging.info(">>>找不到exe窗口")
    else:
        win32gui.CloseWindow(exehd)


# 創建圖像化界面
def create_ui(title):
    root = tkinter.Tk()     # 創建頂層窗口
    root.geometry('400x200')     # 初始化窗口大小
    root.title(title)   # 標題
    # 校驗提示
    check_str = tkinter.StringVar(value='')
    error_label = tkinter.Label(root, textvariable=check_str, anchor='w', background='yellow', foreground='black')
    error_label.place(x=50, y=10, height=20)
    try:
        if check_wins() == 1:
            check_str.set("校驗成功")
        # ip顯示
        ip_str = tkinter.StringVar(value='')
        ip_str.set("本機ip爲: " + get_host_ip())
        ip_label = tkinter.Label(root, textvariable=ip_str, anchor='w')
        ip_label.place(x=50, y=50, height=20)
        # 啓動
        start_button = tkinter.Button(root, text='啓動', command=lambda: create_thread(start_button))
        start_button.place(x=50, y=100, width=50, height=30)
    except Exception as e:
        logging.info(f">>>錯誤信息:{e}")
        check_str.set(e)
        error_label.config(background='red')
    root.mainloop()


# win10系統可能會失敗,安全衛士可能會屏蔽虛擬操作
if __name__ == '__main__':
    create_ui(ui_title)

4.未解決
因爲是模擬虛擬按鍵,所以每次都會彈出qq窗口;
如果設置窗口最小化,在有些機子上虛擬按鍵操作就會失敗,即請求返回成功但是qq窗口沒有黏貼發送;

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章