python 实现微信自动回复(自动聊天)

介绍

微信自动回复其实主要就是登录,接收消息,回复消息三个功能,微信没有提供方便的API,但是可以分析网页版微信通信原理,通过模拟浏览器来实现需要的功能。下面将给出微信网页版通信原理以及Python具体实现代码。

分析


-获取uuid:

GET https://login.wx.qq.com/jslogin?appid=wx782c26e4c19acffb&redirect_uri=https%3A%2F%2Fwx.qq.com%2Fcgi- bin%2Fmmwebwx-bin%2Fwebwxnewloginpage&fun=new&lang=zh_CN&_=1486743163000
Param _ (13位时间戳)
Response window.QRLogin.code = 200; window.QRLogin.uuid = "4YyQFP2Daw==";

-获取二维码:

GEThttps://login.weixin.qq.com/qrcode/4YyQFP2Daw==
Param 4YyQFP2Daw== 即上面的uuid
Response二维码图片

-监听是否扫描二维码以及是否确认登录:

GET https://login.wx.qq.com/cgi-bin/mmwebwx-bin/login?loginicon=true&uuid=4YyQFP2Daw==

Param uuid 同上

Response

window.code=200;window.redirect_uri="https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxnewloginpage?ticket=ARxD7GSdBYtNHOxhK0BF0ek-
@qrticket_0&uuid=4YyQFP2Daw==&lang=zh_CN&scan=1486743186";
code = 408 无响应,201 扫描二维码但没有登录(此时响应数据中还包含用户头像图片base64编码的字符串,UserAvatar) 200 登录
redirect_uri 为接下来需要请求的地址

-获取后续访问所需要的key等

GET https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxnewloginpage?ticket=ARxD7GSdBYtNHOxhK0BF0ek-@qrticket_0&uuid=4YyQFP2Daw==

&lang=zh_CN&scan=1486743186p

Param URL为上次返回的redirect_uri 参数已经带上了

Response

<error><ret>0</ret><message></message><skey>@crypt_828c27e0_e98d62f6954235194f2b1252943f25ad</skey><wxsid>0zEvAdWKm9ZZgYVn</wxsid><wxuin>1564527827</wxuin><pass_ticket>OLxGHwqL%2BWNArxvXaqjDy06qzdrSojq6DJwiBF19sgw2CibZSJBv1WwOXAfKnLIg</pass_ticket><isgrayscale>1</isgrayscale></error>

-初始化

POST https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxinit?r=-485039295&lang=zh_CN&pass_ticket=OLxGHwqL%2BWNArxvXaqjDy06qzdrSojq6DJwiBF19sgw2CibZSJBv1WwOXAfKnLIg

Param r ( - + 9位随机数),pass_ticket,{"BaseRequest": {"Uin": "1564527827", "Skey": "@crypt_828c27e0_e98d62f6954235194f2b1252943f25ad", "DeviceID": "

e924318232435460", "Sid": "0zEvAdWKm 9ZZgYVn"}} 第三个参数其中为json数据,DeviceID为(e + 15位随机数)

Response 返回json,包含用户自己的信息,最近联系人,订阅的公众号消息等等;这里只需要关注 UserName=@821c154488cdddbfb04141aa8f681174305d21d67a24cfd6eca3e77a152e52ff 每位用户都有一个UserName,但是每次登陆UserName都是重新分配的,

SyncKey 为一组key ,后面接收消息需要将其作为参数, 同时每次接收接收消息时,也会返回一组SyncKey作为在下一次请求的参数,以此类推

-状态检查

这里会建立一个长连接,每次连接大约20秒左右,若新消息,手机端发出退出网页登录指令,或者状态异常会返回特定的状态码

GET https://wx.qq.com/cgi-bin/mmwebwx-bin/synccheck?r=1486743215000&skey=@crypt_828c27e0_e98d62f6954235194f2b1252943f25ad&sid=0zEvAdWKm9Z

ZgYVn&uin=1564527827&deviceid=e891796429.95749&synckey=1_660530221%7C2_660530488%7C3_660530485%7C1000_1486721341&_=1486740215000

Param r(时间戳),skey,sid,uin,deviceid,synckey(将SyncKey中的多组key 以 key1_value1|key2_value2 的形式拼接成字符串如:3_660530485|1000_1486721341),_ (时间戳)

Response window.synccheck={retcode:"0",selector:"2"} retcode=0 正常 ,1101 退出登录,1102 会话异常 , selector= 0 无变化 2or6 有消息

-接收消息

若状态检查到有新消息,则请求消息
POST https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxsync?sid=0zEvAdWKm9ZZgYVn&skey=@crypt_828c27e0_e98d62f6954235194f2b1252943f25ad&lang=zh_CN&pass_ticket=OLxGHwqL%2BWNArxvXaqjDy06qzdrSojq6DJwiBF19sgw2CibZSJBv1WwOXAfKnLIg
Param sid,skey,pass_ticket 以及 json数据 {"SyncKey": {"Count": 4, "List": [{"Key": 1, "Val": 660530221}, {"Key": 2, "Val": 660530488}, {"Key": 3, "Val": 660530485}, {"Key": 1000, "Val": 1486721341}]}, "BaseRequest": {"Sid": "0zEvAdWKm9ZZgYVn", "Skey": "@crypt_828c27e0_e98d62f6954235194f2b1252943f25ad", "DeviceID": "e141257009.76972", "Uin": "1564527827"}, "rr": "-888098293"} 其中rr (- + 9位随机数)
Response
json数据包含消息的所有信息,其中关注 FromUserName=@821c154488cdddbfb04141aa8f681174305d21d67a24cfd6eca3e77a152e52ff 消息发送者以及 Content 消息内容

-发送消息

POST h ttps://wx.qq.com/cgi-bin/mmwebwx-bin/webwxsendmsg?lang=zh_CN&pass_ticket=0%2BoUqOWdYEen6oDVFEIv5ncIIaJcWs1LeSi69C8tUTgcp36azGAl6a8uT02PiaHu
Param pass_ticket, json数据{"Msg": {"FromUserName": "@9e718026650771acd6d759922e000fafceaa1a5fda83aea7b3b70bc1bd6c3774", "LocalID": "14867488199507670", "ClientMsgId": "14867488199507670", "ToUserName": "@9e718026650771acd6d759922e000fafceaa1a5fda83aea7b3b70bc1bd6c3774", "Content": "消息内容", "Type": "1"}, "BaseRequest": {"Sid": "5Qn7rswOtPRHFw92", "Skey": "@crypt_828c27e0_ad386b3d4d68a282eda03d7d5b2d3104", "DeviceID": "e397471984070243", "Uin": "1564527827"}, "Scene": "0"} 其中LocalID,ClientMsgId 为13位时间戳加上5位随机数
Response 返回响应的状态码,发送成功会返回 LocalID 和 ClientMsgID


以上就是我们需要的知道的,当然其他比如读取所有联系人等都是大同小异,这里就不多赘述了。
到这里还有关键的一步,那就是如何根据收到的消息自动回复,当然是接入其他可以聊天的程序了,这里为了方便我使用的是牛人趣事的simsimi聊天机器人的外链,它不需要登录等操作,连request header 都不用伪造^0^,直接将接受的消息post过去,将返回的消息作为微信回复消息;当然也可以接入更智能的机器人。

-获取自动回复的消息

POST http://www.niurenqushi.com/api/simsimi/
Param txt (发送的消息)
Response {"code":100000,"text":"消息"}

代码

运行以下代码,会自动弹出二维码图片,手机扫码登录之后开始运行,手机端发送退出登录指令时结束。
重点在于流程和思路,代码也比较糙,注释也就不加了,多指教^0dfd^
# -*- coding:utf-8 -*-
#author:fengw
import urllib,urllib2,cStringIO,re,sys,os,cookielib,ssl,requests,time,json,random,threading,warnings
from PIL import Image
from matplotlib import pyplot as plt
import xml.etree.cElementTree as et 
 
reload(sys)
sys.setdefaultencoding('utf-8')
warnings.filterwarnings("ignore")
 
def get_device_id():
	return 'e'+str(random.random()*10000000000)[0:10]+str(random.random()*100000)[0:5]
def qrcode_img():
	response=urllib2.urlopen(QRCODE_KEY_URL).read()
	p=re.compile(r'(\d+(\.\d+)?)')
	code=p.findall(response)[0][0]
	if  code =='200':
		p=re.compile(r'\"(.*)\"')
		qrcode_key=p.findall(response)[0]
		qrcode_img_url=QRCODE_IMG_BASE_URL+qrcode_key
		global CHECK_LOGIN_STATUS_BASE_URL
		CHECK_LOGIN_STATUS_BASE_URL=CHECK_LOGIN_STATUS_BASE_URL+qrcode_key
		qrcode_img=Image.open(cStringIO.StringIO(urllib2.urlopen(qrcode_img_url).read()))
		plt.ion()
		plt.figure()
		plt.imshow(qrcode_img)
		plt.figure()
		plt.close(2)		
	else :
		print 'sorry,request qrcode failed...'
		time.sleep(2)
		os._exit(0)
		
def listen_login():
	run=True
	times=0
	msg='please scan the qrcode'
	while run:
		times+=1
		print msg
		response=urllib2.urlopen(CHECK_LOGIN_STATUS_BASE_URL).read()
		p=re.compile(r'(\d+(\.\d+)?)')
		code=p.findall(response)[0][0]
		if  code=='201':
			msg= 'please login...'
			plt.close()
		if  code=='200':
			run=False
			plt.close()
			print  'login sucess,running....'
			p=re.compile(r'\"(.*)\"')
			redirect_url=p.findall(response)[0]
			response=conn.get(url=redirect_url,allow_redirects=False,verify=False)
			msg=response.text
			global ret,message,skey,wxsid,wxuin,pass_ticket,isgrayscale
			xml=et.fromstring(msg)
			ret=xml[0].text
			message=xml[1].text
			skey=xml[2].text
			wxsid=xml[3].text
			wxuin=xml[4].text
			pass_ticket=xml[5].text
			isgrayscale=xml[6].text
		
		
		if  times==20:
			run=False
def update_synckey(msg):
	global synckey,syncheck_key
	synckey=str(msg['SyncKey']).replace("u'","'")		
	for k_v in msg['SyncKey']['List']:
		syncheck_key+='|'+str(k_v['Key'])+'_'+str(k_v['Val'])
	syncheck_key=syncheck_key[1:]
def  wx_init():	
	url='https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxinit?r=-485039295&lang=zh_CN&pass_ticket='+pass_ticket	
	data={'BaseRequest':{'DeviceID':'%s'%get_device_id(),'Sid':'%s'%wxsid,'Skey':'%s'%skey,'Uin':'%s'%wxuin}}
	res=conn.post(url=url,headers=headers,data=json.dumps(data),verify=False)
	response=res.text	
	msg=json.loads(response)
	global user
	user=msg['User']['UserName']
	update_synckey(msg)
	
	
def get_contact_list():
	base_url='https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxgetcontact?lang=zh_CN&seq=0'
	base_url+='&pass_ticket='+pass_ticket+'&r='+str(int(time.time())*1000)+'&skey='+skey
	response=urllib2.urlopen(base_url).read()
	data=json.loads(response)
	f=open(r'd:/linklist.txt','w')
	for friend in data['MemberList']:
		msg=friend['NickName']+","+friend['RemarkName']+"\n"
		f.write(msg.encode('utf-8'))
	f.close()
	
def get_auto_reply(send_msg):
	url='http://www.niurenqushi.com/api/simsimi/'
	data={'txt':'%s'%send_msg}
	res=conn.post(url=url,data=data)
	res.encoding='utf-8'
	return  json.loads(res.text,'')['text']
	
 
def reply_msg(content,touser):	
	url='https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxsendmsg?lang=zh_CN&pass_ticket='+pass_ticket
	#touser='filehelper'
	ClientMsgId=str(int(time.time()))+str(random.random()*10000000)[0:7]
	print 'recive msg :',content
	sendmsg=get_auto_reply(content)
	data={'BaseRequest':{'Uin':'%s'%wxuin,'Sid':'%s'%wxsid,'Skey':'%s'%skey,'DeviceID':'%s'%get_device_id()},'Msg':{'ClientMsgId':'%s'%ClientMsgId,'Content':'%s'%sendmsg.encode('utf-8'),'FromUserName':'%s'%user,'LocalID':ClientMsgId,'ToUserName':'%s'%touser,'Type':'1'},'Scene':'0'}
	data=json.dumps(data,ensure_ascii=False)
	res=conn.post(url=url,headers=headers,data=data.encode('utf-8'),verify=False)
	print 'reply:',sendmsg
def recive_msg():
	base_url='https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxsync'
	base_url+='?sid='+wxsid+'&skey='+skey+'&lang='+'zh_CN'+'&pass_ticket='+pass_ticket
	while True:
		try:
			rr='-'+str(random.random()*1000000000)[0:9]
			data={'BaseRequest':{'Uin':'%s'%wxuin,'Sid':'%s'%wxsid,'Skey':'%s'%skey,'DeviceID':'%s'%get_device_id()},'SyncKey':eval(synckey),'rr':'%s'%rr}
			res=conn.post(url=base_url,headers=headers,data=json.dumps(data),verify=False)
			res.encoding='utf-8'
			response=res.text		
			if response==None:
				continue
			data=json.loads(response)
			update_synckey(data)
			for msg in data['AddMsgList']:
				content=msg['Content']
				fromuser=msg['FromUserName']
				if fromuser==user:
					continue
				if content[0:4]=='<':				
					continue
				#print 'recived msg:',content.decode('unicode_escape'),'from user :',fromuser		
				threading.Thread(target=reply_msg,args=(content,fromuser)).start()
			time.sleep(2)
		except Exception  as e :
			pass
		
def sync_check():
	listen=True
	base_url='https://webpush.wx.qq.com/cgi-bin/mmwebwx-bin/synccheck'
	base_url+='?r='+str(int(time.time())*1000)+'&skey='+skey+'&sid='+wxsid+'&uin='+wxuin+'&deviceid='+get_device_id()+'&synckey='+syncheck_key+'&_='+str(int(time.time())*1000-3000000)
	request = urllib2.Request(url=base_url, headers=headers)
	while listen:
		try:
			res=conn.get(url=base_url,headers=headers,verify=False)
			response=res.text
			p=re.compile(r'(\d+(\.\d+)?)')
			retcode=p.findall(response)[0][0]
			if retcode=='1101' or retcode=='1102':
				print 'login out ...'
				listen=False
				os._exit(0)
			time.sleep(2)
		except Exception:
			pass
if __name__ == '__main__':		
	ssl._create_default_https_context = ssl._create_unverified_context
	QRCODE_KEY_URL='https://login.wx.qq.com/jslogin?appid=wx782c26e4c19acffb&redirect_uri=https%3A%2F%2Fwx.qq.com%2Fcgi-bin%2Fmmwebwx-bin%2Fwebwxnewloginpage&fun=new&lang=zh_CN&_='+str(int(time.time())*1000)
	QRCODE_IMG_BASE_URL='https://login.weixin.qq.com/qrcode/'
	CHECK_LOGIN_STATUS_BASE_URL='https://login.wx.qq.com/cgi-bin/mmwebwx-bin/login?loginicon=true&uuid='
	ret,message,skey,wxsid,wxuin,pass_ticket,isgrayscale='','','','','','',''
	synckey,user='',''
	syncheck_key=''
	cookie=cookielib.CookieJar()
	handler=urllib2.HTTPCookieProcessor(cookie)
	debug_h=urllib2.HTTPSHandler(debuglevel=0)
	opener=urllib2.build_opener(handler,debug_h)
	urllib2.install_opener(opener)
	conn=requests.session()
	headers = {     'Host': 'wx.qq.com',
					'Connection': 'keep-alive',
					'Accept': 'application/json, text/plain, */*',
					'Origin': 'https://wx.qq.com',
					'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:51.0) Gecko/20100101 Firefox/51.0',
					'Content-Type': 'application/json;',				
					'Accept-Encoding': 'gzip, deflate, br',
					'Accept-Language': 'zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3'
					}
	#获取微信二维码并显示					
	qrcode_img()
	#监听用户扫描二维码和登录动作
	listen_login()
	#微信初始化
	wx_init()
	#开启子线程监听登录状态
	check_status_task=threading.Thread(target=sync_check)
	check_status_task.start()
	#get_contact_list()
	#主线程监听消息
	recive_msg()

第一次写,请无视排版肯定是编辑器的问题,怎么感觉比word还难

  • 7
    点赞
  • 53
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
### 回答1: 为了编写微信自动回复脚本,我们可以使用itchat库,该库提供了对微信的接口,可以通过Python程序与微信进行交互。 以下是一个简单的微信自动回复脚本示例: ```python import itchat # 回复消息的函数 @itchat.msg_register(itchat.content.TEXT) def reply_msg(msg): if msg['FromUserName'] != myUserName: itchat.send_msg('自动回复:' + msg['Text'], msg['FromUserName']) # 登录微信 itchat.auto_login(hotReload=True) # 获取自己的用户名 myUserName = itchat.get_friends(update=True)[0]["UserName"] # 运行自动回复程序 itchat.run() ``` 这个脚本中,我们使用`itchat.msg_register()`方法注册了一个消息处理函数`reply_msg()`,当收到文本消息时,该函数会自动回复消息内容,并附加上“自动回复”前缀。同时我们使用`itchat.auto_login()`方法登录微信,然后使用`itchat.get_friends()`方法获取自己的用户名,并保存到变量`myUserName`中。最后,我们使用`itchat.run()`方法启动自动回复程序。 值得注意的是,为了使该脚本能够长时间运行,我们需要在登录时设置`hotReload=True`,这样可以让登录状态得到保存,避免重复扫码登录的情况发生。 当我们运行该脚本后,微信中的好友发送消息时,程序会自动回复消息内容,并附加上“自动回复”前缀。 ### 回答2: 使用Python编写微信自动回复脚本是可行的。首先,我们需要安装好Python的运行环境和相关的第三方库,如itchat。然后,通过编写Python脚本,我们可以实现微信好友消息的监听和自动回复。 在脚本中,我们可以使用itchat库的API来实现微信的登录和消息的接收。通过捕获微信好友的文本消息,我们可以根据消息内容编写相应的逻辑来进行回复。例如,可以设置一些关键词回复,当好友发送包含特定关键词的消息时,自动回复相应的内容。 在编写脚本时,我们还可以使用正则表达式等高级技术来匹配和处理消息。例如,可以使用正则表达式来匹配特定格式的消息,并提取其中的信息用于回复。还可以利用其他Python的库来实现更复杂的逻辑,如将接收到的消息进行文本处理、分析等。 此外,我们还可以通过配置文件的方式,使脚本可以针对不同的好友或消息类型进行不同的回复。通过读取配置文件,可以灵活地设置回复规则,实现个性化的自动回复功能。 总结来说,使用Python编写微信自动回复脚本是一种方便且可行的方式。我们可以通过编写Python脚本,利用itchat库的API和其他Python的库,实现微信好友消息的监听和自动回复,从而实现个性化和自动化的微信聊天机器人。 ### 回答3: 使用Python编写微信自动回复脚本需要先安装一些必要的库,比如itchat,它可以模拟微信网页版的操作。 首先,在命令行中安装itchat库,可以使用pip命令:pip install itchat 然后,在Python脚本中导入itchat库:import itchat 接着,使用itchat库的login()函数登录微信账号:itchat.login() 登录成功后可以调用itchat库的函数获取微信好友列表:itchat.get_friends() 接下来,可以使用itchat库的run()函数开启微信消息监听模式,实现自动回复功能:itchat.run() 在run()函数中,可以使用装饰器@itchat.msg_register()来装饰自定义的函数,这个函数将会在收到好友消息时被调用。通过这个函数可以进行消息的处理和回复。 例如,我们可以定义一个回复消息的函数reply_to_friend(msg),其中msg是一个字典包含了收到的消息的具体信息。在函数的内部可以根据消息的类型进行逻辑判断和回复。 最后,运行整个Python脚本,扫描二维码登录微信账号后,即可实现自动回复功能。 需要注意的是,使用微信自动回复脚本有一定的限制,比如在非越狱的iPhone上,微信有防撤回机制,导致不能自动回复撤回消息。同时,使用自动回复脚本也需要谨慎,不要违反微信使用规定,以免被封号。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值