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窗口沒有黏貼發送;