web Smart QQ网页模拟登陆 及接发消息

首先简单说下实现需要的一些模块和基本的思路

1、web smartQQ 提交请求的时候,部分数据需要通过加密后提交,基本上是使用mqcomm.js和mq.js进行加密,

2、使用python,由于不想自己重新实现加密的过程,选择使用了Pyv8的模块,利用web qq 本身的js文件获取加密的函数。


第一部分:登陆webQQ

登陆之前,需要获得相关的verify和puin主要是用于加密密码,verifysession则是用于登陆使用

Vcdic = getCheckVC(uin,login_sig)

def getCheckVC(u,login_sig):
    #主要是获得puin,verity
    #设置提交的数据
    #
    #ReUrl:是Get请求的地址
    ReUrl='https://ssl.ptlogin2.qq.com/check'
    #出来uin和login_sig以后其它的都是网页抓取的,貌似是固定的值
    checkData=[('uin',u),
               ('appid','501004106'),
               ('js_ver','10092'),
               ('js_type','0'),
               ('login_sig',login_sig),
               ('u1','http://w.qq.com/proxy.html'),
               ('r',0.70823077801615),
               ]
    checkData = urllib.urlencode(checkData)
    ReUrl +='?' + checkData
    req = urllib2.Request(ReUrl,headers=headersBase)
    ret = urllib2.urlopen(req)
    strVc=ret.read()
    
    #n:指示是否需要验证码
    #--下面的几个参数均是用于密码的加密
    #verify:
    #puin:
    #versession:
    VcList = re.findall(r'\(.+\)',strVc)
    
    #这里通过的是字典的方式获取,用json处理的时候因为字符的问题报错
    vcdic = dict()
    vctup =''
    exec('vctup ='+VcList[0])
    vcdic['n']=vctup[0]
    vcdic['verify']=vctup[1]
    vcdic['puin'] =  vctup[2]
    vcdic['versession'] =  vctup[3] 
    
    #返回一个包含上面参数的字典
    if vcdic['n'] !='0':
        print u'需要验证码 ,等会再连'
        sys.exit()
        
    #否则设置下面的值
    global verify,verifysession,puin
    verify = vcdic['verify']
    verifysession = vcdic['versession']
    pstr = vcdic['puin']
    #需要对puin进行解码,不然传入pyv8模块进行处理的时候会出现问题,导致加密的密码值不正确 
    puin = pstr.decode('latin1')


然后获得了puin和verify的值,然后进行加密QQ密码

def getpass(apwd,averify,apuin,aString):
    n=apwd
    puin=apuin
    verify=averify
    puin = getStr(puin)
    
    #参考mqcomm.js的加密过程进行加密
    n=md55(n,aString)
    j = hexchar2bin(n,aString)
    h = md55(j+puin,aString)
    h = h+verify
    g = md55(h,aString)
    return g

最后获得加密后的g


登陆webQQ 主要有三部分:

一、通过Get的方式向logUrl ='https://ssl.ptlogin2.qq.com/login'提交数据

主要是u:你的QQ号 p:加密过后的密码,pt_verifysession:上面获得的verify

二、通过上一步获得返回的数据的ptLogUrl,访问该url,目的是获取完整的cookie

三、获取一些用于后面进行发送消息,接受消息及获得好友列表之类需要的一些值

    def logWebqq(u,p,verifycode,pt_verifysession_v1,login_sig):
    global opener,ptwebqq,vfwebqq,psessionid,uin
    logUrl ='https://ssl.ptlogin2.qq.com/login'
    logData =[
            ('u',u),
            ('p',p),
            ('verifycode',verifycode),
            ('webqq_type','10'),
            ('remember_uin','1'),
            ('login2qq','1'),
            ('aid','501004106'),
            ('u1','http://w.qq.com/proxy.html?login2qq=1&webqq_type=10'),
            ('h','1'),
            ('ptredirect','0'),
            ('ptlang','2052'),
            ('daid','164'),
            ('from_ui','1'),
            ('pttype','1'),
            ('dumy',''),
            ('fp','loginerroralert'),
            ('action','0-11-12521'),
            ('mibao_css','m_webqq'),
            ('t','1'),
            ('g','1'),
            ('js_type','0'),
            ('js_ver','10092'),
            ('login_sig',login_sig),
            ('pt_vcode_v1','0'),
            ('pt_verifysession_v1',pt_verifysession_v1),
           ]
    logData = urllib.urlencode(logData)
    
    #Get的方式进行第一次登录,获取初步的cookie的一些值
    logUrl +='?'+logData
    req = urllib2.Request(logUrl,headers=headersBase)
    logtext = opener.open(req)
    logtext =logtext.read()
    
    #获取logtext里面的url,这个url是为下面获取完整cookie进行使用
    #获取ptwebqq的值
    k = re.findall('ptuiCB(.+);',logtext)
    logmess =''
    exec('logmess ='+k[0])
    ptLogUrl = logmess[2]
    #主要是用于进一步获取cookie的值,这里才是真正的登录
    opener.open(ptLogUrl)
    #从cookie获取ptwebqq的值
    for i in ck:
        if i.name == 'ptwebqq':
            ptwebqq = i.value
            break
            
    #Get方式获取http://s.web2.qq.com/api/getvfwebqq数据
    #sWebHeader:在头添加相关的信息
    #sData:提交的数据
    sWebHeader = headersBase
    sWebHeader['Referer'] = 'http://s.web2.qq.com/proxy.html?v=20130916001&callback=1&id=1'
    sData =[
          ('ptwebqq','%s' % ptwebqq),
          ('clientid','53999199'),
          ('psessionid',''),
          ('t',t),
          ]
    sData = urllib.urlencode(sData)
    sDataUrl = 'http://s.web2.qq.com/api/getvfwebqq' + '?'+sData
    req = urllib2.Request(sDataUrl,headers=sWebHeader)
    r = opener.open(req) 
    
    dataReq = r.read()
    #获取vfwebqq的值,用于后面进行好友列表的请求
    dataReq = json.loads(dataReq)
    vfwebqq = dataReq['result']['vfwebqq']
    
    #Post获取:http://d.web2.qq.com/channel/login2的数据
    #这里使用和上面一样的header
    dWebData = [('r',"""{"ptwebqq":"%s","clientid":53999199,"psessionid":"","status":"online"}""" % ptwebqq)]
    dWebData = urllib.urlencode(dWebData)
    req = urllib2.Request('http://d.web2.qq.com/channel/login2',headers=sWebHeader,data=dWebData)
    #获得pseesionid的值
    r = opener.open(req)
    r = r.read()
    dWebDict ={}
    exec('dWebDict = '+r)
    psessionid = dWebDict['result']['psessionid']
    #uin = dWebDict['result']['uin']
    vfwebqq =vfwebqq or dWebDict['result']['vfwebqq']


获取好友列表,这里要注意请求头,基本上都是从网页上面抓取的。

#这里只是做了一个简单的测试,实际上拆分为返回好友列表和查询nickname会比较好些

#获取好友的情况列表,返回指定nickname的uin,用于发送消息使用
def getFriendUin(nickname):
    #获取好友的列表
    #global ptwebqq
    uinStr = str(uin)
    hash = hashValue(uinStr,ptwebqq)
    friendHeaders = headersBase
    #修改请求头的内容
    friendHeaders['Origin'] = 'http://s.web2.qq.com'
    friendHeaders['Host'] = 's.web2.qq.com'
    friendHeaders['Referer'] = 'http://s.web2.qq.com/proxy.html?v=20130916001&callback=1&id=1'
    #friendHeaders['Connection'] = 'keep-alive'
    friendUrl = 'http://s.web2.qq.com/api/get_user_friends2'
    
    friendStr = """{"vfwebqq":"%s","hash":"%s"}"""  % (vfwebqq,hash)
    friendData =[('r',friendStr)]
    friendData = urllib.urlencode(friendData)
    freq = urllib2.Request(friendUrl,headers=friendHeaders)
    friendUin = opener.open(freq,data=friendData)
    
    friendUin2 = friendUin.read()
    #使用json处理数据
    friendUin = json.loads(friendUin2)
    
    #循环查找对应nickname的uin 用于到时发生消息
    for i in friendUin['result']['info']:
        if i['nick'] == nickname:
            nickuin = i['uin']
            print nickuin
            return str(nickuin)


获取消息比较简单,主要是注意请求头,

def getMessage():  
    #ptwebqq,psessionid均为前面获取的值
    #构建pollHeaders请求头
    #Post方式提交数据
    #获取消息的URL:http://d.web2.qq.com/channel/poll2
    #重新获取
    #global opener
    pollUrl = 'http://d.web2.qq.com/channel/poll2'
    pollHeaders = headersBase
    pollHeaders['Origin'] = 'http://d.web2.qq.com'
    pollHeaders['Host'] = 'd.web2.qq.com'
    pollStr = """{"ptwebqq":"%s","clientid":53999199,"psessionid":"%s","key":""}""" %(ptwebqq,psessionid)
    pollData = [('r',pollStr)]
    pollData = urllib.urlencode(pollData)
    
    #Post:发送消息的headers,和消息提交的数据
    #poST:获取好友的列表:http://s.web2.qq.com/api/get_user_friends2
    SmessHeaders = headersBase
    SmessHeaders['Origin'] = 'http://d.web2.qq.com'
    SmessHeaders['Host'] = 'd.web2.qq.com'
    SmessHeaders['Referer'] = 'http://d.web2.qq.com/proxy.html?v=20130916001&callback=1&id=2'
	#'http://s.web2.qq.com/proxy.html?v=20130916001&callback=1&id=1'

    req = urllib2.Request(pollUrl,headers=pollHeaders)
    #opener.open(req,data=pollData)
    
    print u"获取聊天内容中....."
    print u'Start--------------------------------------------------------'
    try:
        r = opener.open(req,data=pollData)
        context = r.read()
        #print context
        print u'--------------华丽的分割线-------------------------------'
        
        print context
        context = json.loads(context)
        print u'\t',context['result'][0]['value']['content'][1]
        print u'\n'*1
        print u'-------'*20
        time.sleep(0.5)
    #主要有两种错误一种是超时导致的,一种是消息太长了 无法获取到
    except KeyError,e:
        print u"获取出错"
        pass
    except Exception,e:
        print e
        pass


发送消息,这个比较麻烦,在发送消息的时候需要先获取消息,并且不能收到消息。

这里只实现发消息的函数

#发送消息的URL:http://d.web2.qq.com/channel/send_buddy_msg2
def sendMessage(nickuin,mess): 
   
    sendHeaders = headersBase
    sendHeaders['Accept'] = r"*/*"
    sendHeaders['Origin'] = 'http://d.web2.qq.com'
    sendHeaders['Host'] = 'd.web2.qq.com'
    sendHeaders['Referer'] = 'http://d.web2.qq.com/proxy.html?v=20130916001&callback=1&id=2'
    #sendHeaders['Connection'] = 'keep-alive'
    #sendHeaders['Content-Length']= 583+len(mess)
    #sendHeaders['Content-Type'] = 'application/x-www-form-urlencoded'
    sendUrl = 'http://d.web2.qq.com/channel/send_buddy_msg2'
    #这个是发送数据用的
    toQQ = nickuin
    content = mess
    #----------------生成随机的msg_id聊天窗口标识---------------------------------------
    z = 0
    #q = time.time()
    q = int(time.time()*1000)
    b = 10**3
    c = 10**4
    q = (q - q % b) / b
    q = q % c * c
    z +=1
    msg_id = str(q + z)
    print msg_id
    
    #―――――――――――――――――――――――――――――--------------------------------------------------------
    #发生消息格式
    messStr = r"""{"to":%s,"content":"[\"%s\\n\",[\"font\",{\"name\":\"宋体\",\"size\":10,\"style\":[0,0,0],\"color\":\"000000\"}]]","face":591,"clientid":53999199,"msg_id":%s,"psessionid":"%s"}"""  % (toQQ,content,msg_id,psessionid)
    
    smessData =[('r',messStr)]
    smessData = urllib.urlencode(smessData)
    sendReq = urllib2.Request(sendUrl,headers=sendHeaders)
    sendMess = opener.open(sendReq,data=smessData)
    print sendMess.read()

最后 附上源码

你可能感兴趣的:(python,Smar,QQ模拟登陆)