pywin32库学习与简单应用

使用pywin32库实现简单的接收和发送QQ消息

    • 简介
    • 准备
    • 接收QQ消息
    • 发送QQ消息
    • 最后

简介

前段时间看到了这篇文章(使用python发送qq消息),是用pywin32实现,感觉很实用,就想学习一下这个库,并实现简单的接收和发送QQ消息(其实就是模拟鼠标键盘行为),这里简单记录一下。pywin32库安装好后里面会有一个.chm的帮助文档,有各个模块的作用和用法。完整代码点击下载。

准备

1.使用python3.6
2.pywin32库

接收QQ消息

首先,需要单独打开对方的QQ聊天界面,再打开和代码同一目录下名为tmp.txt的记事本,程序会首先打开这两个窗口,设置在固定的位置,并设置大小。

def setwindowspos(to_who):#设置两个窗口的大小和位置,失败返回False,成功返回Trueqq_window = win32gui.FindWindow(None, to_who)if qq_window == 0:return Falsewin32gui.ShowWindow(qq_window, 1)win32gui.SetWindowPos(qq_window, win32con.HWND_TOPMOST, 50,50,650,550, win32con.SWP_SHOWWINDOW)tmptxt_window = win32gui.FindWindow(None, 'tmp.txt - 记事本')if qq_window == 0:return Falsewin32gui.ShowWindow(tmptxt_window, 1)win32gui.SetWindowPos(tmptxt_window, win32con.HWND_TOPMOST, 180, 100, 650, 550, win32con.SWP_SHOWWINDOW)return True

模拟鼠标和键盘的函数

def leftclick():#模拟鼠标左键点击,自带延迟0.2swin32api.mouse_event(win32con.MOUSEEVENTF_LEFTDOWN | win32con.MOUSEEVENTF_LEFTUP, 0, 0, 0, 0)time.sleep(0.2)def rightclick():#模拟鼠标右键点击,自带延迟0.2swin32api.mouse_event(win32con.MOUSEEVENTF_RIGHTDOWN | win32con.MOUSEEVENTF_RIGHTUP, 0, 0, 0, 0)time.sleep(0.2)def presskeyboard(key_str):#模拟按键盘,自带延迟0.5s#keybd_event函数的第一个参数是按键的代码win32api.keybd_event(keyboard_table[key_str], 0, 0, 0)win32api.keybd_event(keyboard_table[key_str], 0, win32con.KEYEVENTF_KEYUP, 0)time.sleep(0.5)

初始化函数

def initmain():#完成keyboard_table的赋值alphabet = "abcdefghijklmnopqrstuvwxyz"for i in range(65, 91):keyboard_table[alphabet[i-65]] = ikeyboard_table['shift'] = 16keyboard_table['ctrl'] = 17keyboard_table['alt'] = 18keyboard_table['enter'] = 13

利用ctypes库的windll判断指定一点的颜色,来确定是否有新消息。对方没有发消息那这点就是背景的白色,否则就是聊天框的背景色或字的颜色。

def checknewmessage():#根据像素值变化,判断是否有新消息gdi32 = windll.gdi32user32 = windll.user32#获取句柄hdc = user32.GetDC(None)#获取指定像素的颜色c = gdi32.GetPixel(hdc,120,425)#TIM的背景色是白色0xffffffif c == 16777215:return Falsereturn True

如果有新消息,则在指定位置模拟鼠标右键和键盘C键,完成消息复制,并粘贴到tmp.txt里。然后读取tmp.txt内容,做出相应的回复。

def main():initmain()STATUS = True#判断窗口是否存在,存在则设置两个窗口的大小和位置if setwindowspos(to_who) == False:print("No such window.")return Falsewhile STATUS:qq_window = win32gui.FindWindow(None, to_who)win32gui.ShowWindow(qq_window, 1)win32api.SetCursorPos((120, 425))#检查新消息if checknewmessage() == False:print("No new message.")time.sleep(3)continue#复制QQ接收到的消息rightclick()presskeyboard('c')#将QQ消息复制到本地tmp.txt并保存tmptxt_window = win32gui.FindWindow(None, 'tmp.txt - 记事本')win32gui.ShowWindow(tmptxt_window, 1)win32api.SetCursorPos((750, 425))leftclick()rightclick()presskeyboard('a')rightclick()presskeyboard('p')presskeyboard('alt')presskeyboard('f')presskeyboard('s')#读取本地tmp.txt并进行相应操作f = open('tmp.txt', 'r', encoding = 'UTF-8')r = f.read()f.close()text = str(r.encode('UTF-8'), encoding = "UTF-8").replace('\n', '')text.replace(' ', '')print(text)if text == "exit":print("End interaction.")breakelif len(text) > 25:print("Text is too long.")continueelse:print("Wait for reply.")replymessage(to_who, text)time.sleep(1)

发送QQ消息

程序会根据不用的消息,做出相应回复。

def replymessage(to_who, msg):#根据接收内容进行不同的回复global act#发送setuif msg[0:4] == "setu":sendmessage(to_who, "发送中...")sendimage(to_who, int(msg[4:len(msg)]))#切换APIelif msg[0:3] == "act":act = "act" + msg[3:len(msg)]sendmessage(to_who, "切换功能完成")#使用腾讯API进行回复elif act == "act1":reply_content = tencentapi(msg)sendmessage(to_who, reply_content)#使用青云客API进行回复elif act == "act2":reply_content = qingyunkeapi(msg)sendmessage(to_who, reply_content)

如果接收到"setu+数字“(如setu3),则从某个网站上下载相应数量的图片发送过去。这里用到requests和BeatuifulSoup库,可以看看我的上篇博客,点击这里。

def downloadimage(img_num):#下载图片img_num = min(img_num, 20)se_url = "http://xxxxxxxxxxxx"main_req = requests.get(se_url)main_html = main_req.textmain_soup = BeautifulSoup(main_html, "lxml")cnt = 0for img in main_soup.find_all('img', class_="lazy viewer"):img_url = img.get('data-original')get_img = requests.get(img_url)img_name = 'tmp' + str(cnt) + '.jpg'with open(img_name, 'wb') as f:f.write(get_img.content)f.close()try:Image.open(img_name).verify()except Exception as e:print("Error", e)breakold_img = Image.open(img_name)new_img = 'tmp' + str(cnt) + '.bmp'old_img.save(new_img)cnt += 1if cnt >= img_num:breakreturn min(cnt, img_num)def sendimage(to_who, download_num):#发送图片cur_num = downloadimage(download_num)for i in range(cur_num):#按序将图片写进剪切板里,然后将剪切板内容发送到QQ窗口,并模拟按下Enter键tmp_img_path = "tmp" + str(i) + ".bmp"img = windll.user32.LoadImageW(0, tmp_img_path, win32con.IMAGE_BITMAP, 0, 0, win32con.LR_LOADFROMFILE)setimagetoclipboard(img)qq_window = win32gui.FindWindow(None, to_who)win32gui.SendMessage(qq_window, 770, None, None) #这里770应该是剪切板IDwin32gui.SendMessage(qq_window, win32con.WM_KEYDOWN, win32con.VK_RETURN, 0)win32gui.SendMessage(qq_window, win32con.WM_KEYUP, win32con.VK_RETURN, 0)

上面用的setimagetoclipboard函数

def setimagetoclipboard(img):#复制图片到剪切板cb.OpenClipboard()cb.EmptyClipboard()cb.SetClipboardData(win32con.CF_BITMAP, img)cb.CloseClipboard()def getimagefromclipboard(hwnd):#获取剪切板图片cb.OpenClipboard(hwnd)cb_img = cb.GetClipboardData(win32con.CF_BITMAP)cb.CloseClipboard()return cb_img    

如何接收到"act+数字"(如act2),则切换使用的API。这里用到的是腾讯智能闲聊和青云客,这里有篇文章介绍如何使用腾讯API,腾讯AI开放平台里面还有很多API可以用,改一下链接和参数就可以了。

def sendmessage(to_who, msg):#发送文本信息print(msg)setmessagetoclipboard(msg)qq_window = win32gui.FindWindow(None, to_who)win32gui.ShowWindow(qq_window, 1)win32api.SetCursorPos((120, 545))rightclick()presskeyboard("p")presskeyboard("enter")def tencentapi(content):#使用腾讯聊天APIapi_url = 'https://api.ai.qq.com/fcgi-bin/nlp/nlp_textchat'content_plus = content.encode('UTF-8')payload = md5sign.getparams(content_plus)cnt = 0r = requests.post(api_url, data=payload)while cnt < 5 and str(r) == "":r = requests.post(api_url, data=payload)cnt += 1return r.json()['data']['answer']def qingyunkeapi(content):#使用青云客的APIapi_url = "http://api.qingyunke.com/api.php?key=free&appid=0&msg=" + contentcnt = 0r = requests.get(api_url)while cnt < 5 and str(r) == "":r = requests.get(api_url)cnt += 1return r.json()['content']

上面用的setmessagetoclipboard函数

def setmessagetoclipboard(msg):#复制文本到剪切板cb.OpenClipboard()cb.EmptyClipboard()cb.SetClipboardData(win32con.CF_UNICODETEXT, msg)cb.CloseClipboard()def getmessagefromclipboard(hwnd):#获取剪切板文本cb.OpenClipboard(hwnd)cb_msg = cb.GetClipboardData(win32con.CF_UNICODETEXT)cb.CloseClipboard()return cb_msg

最后

上面贴出来的代码只是部分,完整代码可以从开头链接处下载。这里主要用到了win32con,win32gui,win32api,win32clipboard等几个模块。感觉pywin32还是很实用的一个库,后续再深入了解一下。

Published by

风君子

独自遨游何稽首 揭天掀地慰生平

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注