用Python做一个基于OCR的微信聊天机器人

用Python做一个基于OCR的微信聊天机器人

该脚本为博主个人开发使用,当前已满足自身需要,是低配版的聊天机器人,为了节约您的时间,这里先把该脚本原理以及缺点说一下,看完再自行决定是否往下看正文.
原理:

  • 利用微信PC客户端的聊天窗口截图,进行文字识别
  • 识别到有新消息,将聊天内容发给聊天机器人接口
  • 模拟鼠标键盘操作,在聊天窗口粘贴接口返回的对话内容,进行发送

缺点

  • 仅支持单个窗口的聊天对话,也就是同一时间只能和一个好友或者群组对话
  • 会模拟鼠标键盘的操作,所以在脚本启动的时候,尽量不要操作电脑
  • 聊天窗口需要在屏幕上固定的位置显示,并且不能被其他窗口遮挡
  • 仅支持文本消息,并且文本消息内容不能过长

小优点

  • 只要页面符合微信的聊天,理论上可以用于任何的聊天窗口,原理上可行,但是未做验证

以下是正文




前几年了解到在Python上有一个叫itchat的项目,就是利用wechatpy和图灵机器人的接口结合,实现一个可以自动回复微信好友消息或者群组消息的机器人,机器人支持天气,笑话,百科,闲聊之类的对话,之前自己照着教程集成实现了可以自动对话的功能,感觉还蛮有趣的,不过当时玩了一阵子就没有再继续接触了.

过了两年后的今天,想再次用itchat实现聊天机器人的时候,发现了几个问题,

一个是我的微信号被限制了WEB网页端登录,同事的微信号登录网页版是正常的,而我的号登录的时候却提示:
为了你的帐号安全,此微信号不能登录网页微信。你可以使用Windows微信或Mac微信在电脑端登录。Windows微信下载地址:https://pc.weixin.qq.com Mac微信下载地址:https://mac.weixin.qq.com
另一个是图灵机器人的免费调用次数变少了,以前我记得是几百次一天的,现在未认证的不给调用了,认证了一天也只有可怜的100次/天
简而言之就是一句话:wechatpy我用不了了,于是自己想了其他的办法,花了四个小时做了一个属于自己开发的微信机器人,该脚本理论上不仅限于微信,应该还能用在其他聊天窗口,这里未做验证



原理

  • 进行屏幕截图将微信PC端好友聊天的话泡处提取出来,进行判断是否有新的消息,截取的区域如下图所示,注意截图所示的红框区域的左上角和右下角

在这里插入图片描述

  • 其中红框处的左上角坐标是是截图的起始坐标,也是判断是否有收到消息的判断方式,因为文字识别调用的是百度提供的服务,有一定的次数限制,一天免费额度5000次,虽然够用,但是能减少系统消耗就尽量减少消耗,所以这里根据进行了判断是否有收到好友消息。利用了聊天窗口的背景色,我的客户端背景色是RGB(245,245,245),所以当有好友发送消息的时候,这里会被好友头像挡住,大概率出现RGB不是(245,245,245)的情况,可以利用这一特点进行判断是否收到好友消息
  • 上图红框处故意将框的长度延长了一点,是为了尽量能读取到收到的长文本消息。之后就将红框截图保存成文件,然后调用百度的OCR接口,上传识别。

截图使用的是PIL库,安装:

pip install pillow

截图保存相关代码:

	from PIL import ImageGrab
	from PIL import Image
	
	#微信头像部分起始像素
	wechatHeadPx = 1350
	wechatHeadPy = 893
	#话泡最长度底部像素
	wechatMsgEndPx = 1686
	wechatMsgEndPy = 920
	# 截图保存,输入屏幕左上角和右下角的坐标
    pic = ImageGrab.grab(bbox=(wechatHeadPx, wechatHeadPy, wechatMsgEndPx, wechatMsgEndPy))
    pic.save(saveFileName)

判断像素是否相同代码:

	 piex = pic.getpixel((0,0))#获取像素点值,返回(37, 37, 38)
	 wechatEmptyPiex = (245,245,245)#微信聊天界面空白处的像素值
     if piex!=wechatEmptyPiex:
		#有收到好友消息,该处是会被头像挡住的点
		pass

OCR的api相关链接,(APPID,apikey,SECRET_KEY自行申请获取)

百度文字识别

百度文字识别文档

安装百度OCR:

pip install baidu-aip

图片识别代码:

	#百度ai
	from aip import AipOcr
	""" 读取图片 """
	def get_file_content(filePath):
	    with open(filePath, 'rb') as fp:
	        return fp.read()

	""" 你的 APPID AK SK """
	BAIDU_OCR_APP_ID = '123456'
	BAIDU_OCR_API_KEY = '123456'
	BAIDU_OCR_SECRET_KEY = '123456'
	
	client = AipOcr(BAIDU_OCR_APP_ID, BAIDU_OCR_API_KEY, BAIDU_OCR_SECRET_KEY)
	saveFileName = "1.jpg"
    image = get_file_content(saveFileName)
    bs = client.basicGeneral(image);
    print(bs)

上面代码关键key自行替换为自己申请的

  • 获取到识别结果之后,就需要进行调用聊天机器人接口了,在这个步骤我了解了一些各种聊天机器人,最终决定使用百度的UNIT,功能还蛮强大的,方便拓展.当然现在完全够用了,各位可以使用其他的也行。

百度unit聊天机器人

百度unit聊天机器人文档

目前该应用免费使用,这里需要注意的是,申请了之后需要添加一些技能才行,我就添加了天气,百科,闲聊这些基本的。还有就是要去技能那里看看,找到闲聊对应的技能ID,后面要用。

聊天相关代码:

	BAIDU_UNIT_API_KEY = "123456"
	BAIDU_UNIT_SECRET_KEY = "123456"
	#下面要替换成自己的bot_id,是你的技能ID!!,这里我用的是闲聊技能ID
	bot_id='123456'
	def getBaiDuAK():
	    # client_id 为官网获取的AK, client_secret 为官网获取的SK
	    host = 'https://aip.baidubce.com/oauth/2.0/token?grant_type=client_credentials&client_id='+BAIDU_UNIT_API_KEY+"&client_secret="+BAIDU_UNIT_SECRET_KEY
	    r = requests.get(host)
	    return r.json()['access_token']
	 
	def baiduApi(text):
	    global access_token
	    url = 'https://aip.baidubce.com/rpc/2.0/unit/bot/chat?access_token=' + access_token
	    query = text
	    #下面的log_id在真实应用中要自己生成,可是递增的数字
	    log_id ='7758521'
	    #下面的user_id在真实应用中要是自己业务中的真实用户id、设备号、ip地址等,方便在日志分析中分析定位问题
	    user_id='222333'
	    
	    post_data = '{\"bot_session\":\"\",\"log_id\":\"'+log_id+'\",\"request\":{\"bernard_level\":1,\"client_session\":\"{\\\"client_results\\\":\\\"\\\", \\\"candidate_options\\\":[]}\",\"query\":\"' + query + '\",\"query_info\":{\"asr_candidates\":[],\"source\":\"KEYBOARD\",\"type\":\"TEXT\"},\"updates\":\"\",\"user_id\":\"'+user_id+'\"},\"bot_id\":'+bot_id+',\"version\":\"2.0\"}'
	    print (json.loads(post_data))
	    headers = {'Content-Type':'application/json'}
	    r = requests.post(url, data=post_data.encode('utf-8'),headers=headers)
	    responseJson = r.json()['result']['response'];
	    action_list = responseJson[ 'action_list' ]
	    print ( action_list )
	    if len(action_list)>0:
	        return action_list[random.randint(0,len(action_list)-1)]['say']

	 res = baiduApi( "你好啊!" )
     print( res )	

api接入博客参考

其他免费聊天机器人参考1

其他免费聊天机器人参考2

其他免费聊天机器人参考3

  • 将结果返回给好友

这里利用的是模拟鼠标键盘操作,首先是将文本结果复制到剪贴板,然后模拟鼠标点击消息输入区域,使其焦点在输入框,再模拟粘贴操作将文本粘贴上去,最后模拟回车发送操作

需要用到的库

	import pyperclip #python实现复制粘贴
	
	import pymouse,pykeyboard
	from pymouse import *
	from pykeyboard import PyKeyboard

pip install pyperclip

pip install PyKeyboard

注意

PyUserInput模块

安装该库好像需要先装PyHook,直接用pip命令还安装不上,所以需要下载文件来安装。

PyHook下载页面

参考资料

相关代码:

	myMsgWindowHeadD = 1000
	res = "聊天机器人返回结果"
	print( res )
    pyperclip.copy( res )

    #点击
    myMouse = PyMouse()
    myMouse.click(wechatHeadPx,wechatHeadPy + myMsgWindowHeadD)
    pasteText()
    k = PyKeyboard()
    k.press_key(k.enter_key) #回车键

上面点击区域是用图片中红框左上角往下移动1000像素,因为好友头像处的1000像素正下方刚好是我PC端的消息输入窗口,所以模拟鼠标单击此处就可以让消息输入框获取焦点,再进行模拟Ctrl+V粘贴,回车动作,完成消息发送。

代码说明结束------------------------------


tip:

  • 可以使用win+左,或者win+右使微信客户端刚好占满半屏,我这里用的是右半屏,所以好友的聊天位置是每次都固定的,(只要没双屏,换显示器)
  • 上述步骤完成之后,可以将窗口顶部往下拉,调的小一点都无所谓,这样占用的区域就不会太大了。

完整代码

部分代码需要替换成自己的key,像素位置信息需要自己通过截屏获取区域像素点,每台电脑情况不一样,参数设置完成后,才可以完成功能

	import requests
	from PIL import ImageGrab
	from PIL import Image
	import pytesseract
	
	import pyperclip #python实现复制粘贴
	
	import pymouse,pykeyboard,os,sys
	from pymouse import *
	from pykeyboard import PyKeyboard
	
	import requests
	import json
	import random
	import time
	
	#百度ai
	from aip import AipOcr
	
	 
	
	
	saveFileName = "1.jpg"
	wechatEmptyPiex = (245,245,245)#微信聊天界面空白处的像素值
	
	#微信头像部分起始像素
	wechatHeadPx = 1350
	wechatHeadPy = 893
	#话泡最长度底部像素
	wechatMsgEndPx = 1686
	wechatMsgEndPy = 920
	#我的聊天窗口和好友头像的像素差距
	myMsgWindowHeadD = 1000
	
	
	    
	
	""" 你的 APPID AK SK """
	BAIDU_OCR_APP_ID = '123456789'
	BAIDU_OCR_API_KEY = '123456789'
	BAIDU_OCR_SECRET_KEY = '123456789'
	
	client = AipOcr(BAIDU_OCR_APP_ID, BAIDU_OCR_API_KEY, BAIDU_OCR_SECRET_KEY)
	
	
	#百度unit参数
	BAIDU_UNIT_API_KEY = "123456789"
	BAIDU_UNIT_SECRET_KEY = "123456789"
	#下面要替换成自己的bot_id,是你的技能ID!!,这里我用的是闲聊技能ID
	bot_id='123456789'
	def getBaiDuAK():
	    # client_id 为官网获取的AK, client_secret 为官网获取的SK
	    host = 'https://aip.baidubce.com/oauth/2.0/token?grant_type=client_credentials&client_id='+BAIDU_UNIT_API_KEY+"&client_secret="+BAIDU_UNIT_SECRET_KEY
	    r = requests.get(host)
	    return r.json()['access_token']
	 
	def baiduApi(text):
	    global access_token
	    url = 'https://aip.baidubce.com/rpc/2.0/unit/bot/chat?access_token=' + access_token
	    query = text
	    #下面的log_id在真实应用中要自己生成,可是递增的数字
	    log_id ='7758521'
	    #下面的user_id在真实应用中要是自己业务中的真实用户id、设备号、ip地址等,方便在日志分析中分析定位问题
	    user_id='222333'
	    
	    post_data = '{\"bot_session\":\"\",\"log_id\":\"'+log_id+'\",\"request\":{\"bernard_level\":1,\"client_session\":\"{\\\"client_results\\\":\\\"\\\", \\\"candidate_options\\\":[]}\",\"query\":\"' + query + '\",\"query_info\":{\"asr_candidates\":[],\"source\":\"KEYBOARD\",\"type\":\"TEXT\"},\"updates\":\"\",\"user_id\":\"'+user_id+'\"},\"bot_id\":'+bot_id+',\"version\":\"2.0\"}'
	    print (json.loads(post_data))
	    headers = {'Content-Type':'application/json'}
	    r = requests.post(url, data=post_data.encode('utf-8'),headers=headers)
	    responseJson = r.json()['result']['response'];
	    action_list = responseJson[ 'action_list' ]
	    print ( action_list )
	    if len(action_list)>0:
	        return action_list[random.randint(0,len(action_list)-1)]['say']
	 
	
	
	""" 读取图片 """
	def get_file_content(filePath):
	    with open(filePath, 'rb') as fp:
	        return fp.read()
	
	"""模拟键盘粘贴操作"""
	def pasteText():
	    k = PyKeyboard()
	    #模拟键盘点击ctrl+v
	    k.press_key(k.control_key)
	    k.tap_key('v')
	    k.release_key(k.control_key)
	    time.sleep(1)#速度别太快
	
	
	global access_token  #在使用前初次声明
	access_token =getBaiDuAK()
	
	
	print( "\n" )
	
	
	
	lastMsg = "";#上一次消息
	def getLastMsgStr():#运行一次截取消息并且进行识别
	    # 截图保存,输入屏幕左上角和右下角的坐标
	    pic = ImageGrab.grab(bbox=(wechatHeadPx, wechatHeadPy, wechatMsgEndPx, wechatMsgEndPy))
	    pic.save(saveFileName)
	
	
	    piex = pic.getpixel((0,0))#获取像素点值,返回(37, 37, 38)
	
	    if piex!=wechatEmptyPiex:
	        #说明不是空消息,有获取到头像像素信息
	        image = get_file_content(saveFileName)
	
	        """ 调用通用文字识别, 图片参数为本地图片 """
	        bs = client.basicGeneral(image);
	        print(bs)
	        print("图片识别结果数量" + str( bs["words_result_num"] ))
	        if bs["words_result_num"]>0:#识别到有结果
	           resultSet = bs["words_result"]
	           resultStr = resultSet[0]["words"]#识别到的文字
	           print("识别到聊天的文字为:"+ resultStr )
	           global lastMsg
	           #跟之前的聊天消息进行对比,看看是不是重复了
	           if lastMsg is not resultStr:
	           
	               lastMsg = resultStr#刷新最后消息
	               return resultStr
	
	while True:
	    strLastMsg = getLastMsgStr()
	    if strLastMsg is not None:
	        print("返回识别文字为:"+ str( strLastMsg ))
	        res = baiduApi( strLastMsg )
	        print( res )
	        pyperclip.copy( res )
	
	        #点击
	        myMouse = PyMouse()
	        myMouse.click(wechatHeadPx,wechatHeadPy + myMsgWindowHeadD)
	        pasteText()
	        k = PyKeyboard()
	        k.press_key(k.enter_key) #回车键
	    time.sleep(5)#速度别太快
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值