首页 > 上网技巧 > 电脑小技巧 > python实现微信自动回复自动聊天

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

时间:2017-08-06 11:06 作者:QQ地带 我要评论

介绍 
微信自动回复其实主要就是登录,接收消息,回复消息三个功能,微信没有提供方便的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": "0zEvAdWKm9ZZgYVn"}} 第三个参数其中为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                                         https://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^
[python] view plain copy print?
# -*- 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,'<span style="font-family: Arial, Helvetica, sans-serif;">Content':'%s'%sendmsg.encode('utf-8'),'FromUserName':'%s'%user,'LocalID':ClientMsgId,'ToUserName':'%s'%touser,'Type':'1'},'Scene':'0'}</span>  
[python] view plain copy print?
data=json.dumps(data,ensure_ascii=False)  
res=conn.post(url=url,headers=headers,data=data.encode('utf-8'),verify=False)  
print 'reply:',sendmsg  
ef 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  
      
ef 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  
f __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()  

标签: Python
顶一下
(0)
0%
踩一下
(0)
0%

Google提供的广告