• python实现QQ机器人(自己主动登录,获取群消息,发送群消息)


    一次偶然的机会我看见了一个群里的一个QQ号总是依据你所发的消息自己主动回复,当时非常感觉到奇妙。我知道能够模拟登录站点,没想到居然也能模拟登录QQ,首先自己想到的就是怎样实现模拟登录PC端的QQ, 開始研究了下,发现QQ所发送的包都非常难理解。

    于是就转到了网页版的QQ,由于在网页里能够捕获全部的请求从而更好的实现模拟功能!

    首先第一步就是打开网页版的qq。打开浏览器的开发人员模式 这里能够监控全部的请求!

    打开登录界面的的时候

     

    会捕捉到一个GET请求

    https://ssl.ptlogin2.qq.com/check?uin=10588690&appid=1003903&js_ver=10080&js_type=0&login_sig=YW1ZUUsIU*7FepsR1blgEgcSVWeHCrNVVquTT1LZ0paOxZ-6xHtypEqNGoo-VELQ&u1=http%3A%2F%2Fweb2.qq.com%2Floginproxy.html&r=0.5928007187321782

    当中uin是你的QQ号

    返回值是 ptui_checkVC('1','AAr4bdjMeh2hEa77PTuoHhqMTxbRqOp3','x00x00x00x00x00xa1x92x12');

    当中1表示须要验证码 另一种返回值 ptui_checkVC('0','!LJV','x00x00x00x00x00xa1x92x12') 这样的表示是不须要的验证码的

    def CheckVerify(self,uin):
            check="https://ssl.ptlogin2.qq.com/check?uin={uin}&appid=1003903&js_ver=10080&js_type=0&login_sig=YPD0P*wu2n8vW1OS2f7VfzvPf3Ku5vnkP4nzImF0GybR02fsKZdjGYB7f9R7nQRn&u1=http%3A%2F%2Fweb2.qq.com%2Floginproxy.html&r=0.8179273759014904"
            check=check.replace('{uin}',uin)
            pattern=re.compile("ptui_checkVC('(.*)','(.*)','(.*)');")
            result=self.Get(check)
            checked= pattern.search(result).groups()
            print 'Step1: CheckVerify'
            return checked

    获取验证码的方法

    def GetVerify(self):
            #url = 'https://ssl.captcha.qq.com/getimage?

    &uin='+str(self.QQ)+'&aid=1002101&0.45644426648505' + str(random.randint(10,99)) verify="https://ssl.captcha.qq.com/getimage?aid=1003903&r=0.6472875226754695&uin={QQ}&cap_cd=aSD-ZVcNEcozlZUurhNYhp-MBHf4hjbJ" verify=verify.replace('{QQ}',self.QQ) path= r"c:/verify/1.jpg" #data = urllib.urlretrieve(url,path) data = urllib2.urlopen(verify) localPic =open(r"c:/verify/1.jpg",'wb') localPic.write(data.read()) localPic.close() data.close()

    输入username和password 还有验证码后发送一个GET请求

    https://ssl.ptlogin2.qq.com/login?

    u=10588690&p=AB80CD3B6429D9660878E93058DD78BD&verifycode=TEYX&webqq_type=10&remember_uin=1&login2qq=1&aid=1003903&u1=http%3A%2F%2Fweb2.qq.com%2Floginproxy.html%3Flogin2qq%3D1%26webqq_type%3D10&h=1&ptredirect=0&ptlang=2052&daid=164&from_ui=1&pttype=1&dumy=&fp=loginerroralert&action=6-14-296574&mibao_css=m_webqq&t=1&g=1&js_type=0&js_ver=10080&login_sig=YW1ZUUsIU*7FepsR1blgEgcSVWeHCrNVVquTT1LZ0paOxZ-6xHtypEqNGoo-VELQ&pt_uistyle=5

    这里面u代表账号  p代表password password是经过一定算法加密的 verify是验证码

    加密算法例如以下

        def PasswordSecret(self,password,v1,v2,md5=True):
            if md5==True:
                password=self.PCMd5(password).upper()
            length=len(password)
            temp=''
            for i in range(0,length,2):
                temp+=r'x'+password[i:i+2]
            return self.PCMd5(self.PCMd5(self.hex2asc(temp)+self.hex2asc(v2)).upper()+v1).upper()
    
    
    #md5加密函数
        def PCMd5(self,s):
            h=hashlib.md5()
            h.update(s)
            return h.hexdigest()
        #16进制转字符
        def hex2asc(self,s):
            _str="".join(s.split(r'x'))
            length=len(_str)
            data=''
            for i in range(0,length,2):
                data+=chr(int(_str[i:i+2],16))
            return data


     

    然后是登录部分代码

    def Login(self,uin,pwd):
            #获取參数
            cheked=self.CheckVerify(uin)
            #加密password
            #pwd=self.PasswordSecret(pwd,cheked[1],cheked[2])
            #pwd=self.PasswordSecret(pwd,r'AAST',r'x00x00x00x00x00xa1x92x12')
            loginurl="https://ssl.ptlogin2.qq.com/login?

    u={uin}&p={pwd}&verifycode={verify}&webqq_type=10&remember_uin=1&login2qq=1&aid=1003903&u1=http%3A%2F%2Fweb2.qq.com%2Floginproxy.html%3Flogin2qq%3D1%26webqq_type%3D10&h=1&ptredirect=0&ptlang=2052&daid=164&from_ui=1&pttype=1&dumy=&fp=loginerroralert&action=4-30-135914&mibao_css=m_webqq&t=1&g=1&js_type=0&js_ver=10080&login_sig=YPD0P*wu2n8vW1OS2f7VfzvPf3Ku5vnkP4nzImF0GybR02fsKZdjGYB7f9R7nQRn&pt_uistyle=5" loginurl=loginurl.replace('{uin}',uin) #loginurl=loginurl.replace('{pwd}',pwd) #loginurl=loginurl.replace('{verify}',cheked[1]) #result=Get(loginurl) if(cheked[0]=="1"): #下载验证码 self.GetVerify() image = Image.open(r"c:/verify/1.jpg") image.show() code=raw_input("verifycode:").strip() loginurl=loginurl.replace('{verify}',code.upper()) pwd=self.PasswordSecret(pwd,r''+code.upper(),cheked[2]) #pwd=self.PasswordSecret(pwd,cheked[1],cheked[2]) else: loginurl=loginurl.replace('{verify}',cheked[1]) pwd=self.PasswordSecret(pwd,cheked[1],cheked[2]) loginurl=loginurl.replace('{pwd}',pwd) result=self.Get(loginurl,'ssl.ptlogin2.qq.com','https://ui.ptlogin2.qq.com/cgi-bin/login?daid=164&target=self&style=5&mibao_css=m_webqq&appid=1003903&enable_qlogin=0&no_verifyimg=1&s_url=http%3A%2F%2Fweb2.qq.com%2Floginproxy.html&f_url=loginerroralert&strong_login=1&login_state=10&t=20140514001',None) print 'Step2: Login' pattern=re.compile("ptuiCB('(.*)','(.*)','(.*)','(.*)','(.*)',s'(.*)');") ret= pattern.search(result).groups() #获取必要的cookie 否则第二次登陆会出错 self.Get(ret[2]) print 'Step3: GetCookie' for c in self.cj: if c.name=="ptwebqq": self.ptwebqq=c.value return result


    登录成功后server会返回一串json数据

    ptuiCB('0','0','http://ptlogin4.web2.qq.com/check_sig?pttype=1&uin=10588690&service=login&nodirect=0&ptsig=*ZwU0pfTmYP93Fbdt6uSzbbODzlZ0EY9g25PDge5zZU_&s_url=http%3A%2F%2Fweb2.qq.com%2Floginproxy.html%3Flogin2qq%3D1%26webqq_type%3D10&f_url=&ptlang=2052&ptredirect=100&aid=1003903&daid=164&j_later=0&low_login_hour=0&regmaster=0&pt_login_type=1&pt_aid=0&pt_aaid=0&pt_light=0','0','登录成功!

    ', '小竹');

    第一个为0 就表示登录成功了 ,可是这并没有真正的登录成功

    上面的返回值中的url是用来获取一个关键cookie的 那就是ptwebqq

    然后进行第二次登录,这次才是真正的登录

    http://d.web2.qq.com/channel/login2

    请求例如以下

      1. Accept:
        */*
      2. Accept-Encoding:
        gzip,deflate,sdch
      3. Accept-Language:
        zh-CN,zh;q=0.8
      4. Connection:
        keep-alive
      5. Content-Length:
        244
      6. Content-Type:
        application/x-www-form-urlencoded
      7. Cookie:
        o_cookie=455910092; RK=fMEaWEZ0Qc; ts_last=web2.qq.com/; ts_refer=www.baidu.com/; ts_uid=4588821804; pgv_pvid=914251705; pgv_info=ssid=s3525422600&pgvReferrer=; verifysession=h02LeYrtarkWBZeSu_czkiczeNSNlDm7V1mCm-A5qatkwnHaNfgb2z46zH4X7OfyhFT7wH6LfschPvSLhDGXFA4eA**; ptui_loginuin=10588690; ptisp=cnc; ptcz=dace9cf90e7064a16ee56c8153273eff9f2de1d2827ba31f6571412ac18c50c3; ptwebqq=b21232ed3519839063d1c2ead8a8588c385d168097efdf88bc56e1a78be7dfb4; pt2gguin=o0010588690; uin=o0010588690; skey=@gmEO6N2JD; p_uin=o0010588690; p_skey=cZ5*kS-NOcXlD2Q0AEpJnmExwC2yA0g7jbTygpVFiA8_; pt4_token=1SyuJ39Eq6oKEwEhGIizeg__
      8. Host:
        d.web2.qq.com
      9. Origin:
        http://d.web2.qq.com
      10. Referer:
        http://d.web2.qq.com/proxy.html?v=20110331002&callback=1&id=2
      11. User-Agent:
        Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/34.0.1847.116 Safari/537.36
    1. Form Dataview sourceview URL encoded
      1. r:
        {"status":"online","ptwebqq":"b21232ed3519839063d1c2ead8a8588c385d168097efdf88bc56e1a78be7dfb4","passwd_sig":"","clientid":"7963288","psessionid":null}
      2. clientid:
        7963288
      3. psessionid:
        null

    当中的ptwebqq就是刚才我们从cookie中获取的

    这部分代码是

    def Login2(self):
            try:
                url="http://d.web2.qq.com/channel/login2"
                postdata="r=%7B%22status%22%3A%22online%22%2C%22ptwebqq%22%3A%22{$ptwebqq}%22%2C%22passwd_sig%22%3A%22%22%2C%22clientid%22%3A%22{$clientid}%22%2C%22psessionid%22%3Anull%7D&clientid={$clientid}&psessionid=null"
                postdata=postdata.replace("{$ptwebqq}",self.ptwebqq)
                postdata=postdata.replace("{$clientid}",str(self.clientid))
                print 'Step4: Login2'
                result=self.Post(url,postdata,QQRobot.HOST[0],QQRobot.REFERER[0],QQRobot.ORIGIN[0])
                retjson=json.loads(result)
                retjson=retjson["result"]
                return retjson
            except Exception,e:
                    print "Login2 error "+str(e)


     

    第二次登陆成功后会返回一个

     '''{"retcode":0,
        "result":{
                  "uin":10588690,
                  "cip":1707901841,
                  "index":1075,
                  "port":59571,
                  "status":"online",
                  "vfwebqq":"c043f1f6ce5c3b76a4603ab60082668bef2dde0b987808f728e2071eb7c164eeb30fcd85c31018d2",
                  "psessionid":"8368046764001d636f6e6e7365727665725f77656271714031302e3133392e372e31363000006cb000001ae1036200a192126d0000000a40356c593742635175316d00000028c043f1f6ce5c3b76a4603ab60082668bef2dde0b987808f728e2071eb7c164eeb30fcd85c31018d2",
                  "user_state":0,
                  "f":0
                  }
        }'''

     这种数据结构  当中0表示登陆成功

    须要把这写数据保存下来 后面进行操作须要


    登陆成功后我们就能够拉去群列表了

    #获取群列表信息
        def GetGroupNameList(self,vfwebqq):
            try:
                url="http://s.web2.qq.com/api/get_group_name_list_mask2"
                postdata="r=%7B%22vfwebqq%22%3A%22{$vfwebqq}%22%7D"
                postdata=postdata.replace("{$vfwebqq}",vfwebqq)
                ret=self.Post(url,postdata,QQRobot.HOST[1],QQRobot.REFERER[1],QQRobot.ORIGIN[1])
                print 'Step5: GetGroupList'
                retjson=json.loads(ret)
                retjson=retjson["result"]
                self.grouplist=retjson
                for group in self.grouplist['gnamelist']:
                    print group["code"],group["name"]
                    
            except Exception,e:
                print "GetGroupNameList error"+str(e)
    #获取群成员信息
        def GetGroupInfo(self,gcode,vfwebqq):
            try:
                url="http://s.web2.qq.com/api/get_group_info_ext2?gcode={$gcode}&cb=undefined&vfwebqq={$vfwebqq}&t=1402069438458"
                url=url.replace("{$vfwebqq}",vfwebqq)
                url=url.replace("{$gcode}",str(gcode))
                ret=self.Get(url,QQRobot.HOST[1],QQRobot.REFERER[1],None)
                print "Step6: GetGroupInfo"
                retjson=json.loads(ret)
                retjson=retjson["result"]
                self.groupuserlist=retjson
            except Exception,e:
                print "GetGroupInfo error"+str(e)

    #发送群消息
        def SendGroupMsg(self,groupid,msg,psessionid):
            try:
                #msg=u">:"+msg
                #msg=msg.strip()
                #urlmsg=quote(msg.encode('utf8'))
                #把普通字符串包裹起来
                stype="%5C%22{content}%5C%22"
                temp=""
                part=""
                for c in msg:
                    if type(c) is types.ListType:
                        
                        part=quote(str(c).strip().encode('utf8'))+"%2C"
                        #part=part.replace("%20","")
                        part=part.replace("%27","%5C%22") #把 ' 换为 "
                        part=part.replace("u","") #把 u 换为 空
                        temp+=part
                    else:
                        temp+=stype.replace("{content}",quote(c.encode('utf8')))+"%2C"
                temp=temp[0:len(temp)-3]
                
    
                #urlmsg="%5C%228%5C%22"#"%5B%5C%22face%5C%22%2C13%5D"
                urlmsg=temp
                url="http://d.web2.qq.com/channel/send_qun_msg2"
                msg_id = 77860003
                #postdata="r=%7B%22group_uin%22%3A{$group_uin}%2C%22content%22%3A%22%5B%5C%22{$msg}%5C%22%2C%5C%22%5C%22%2C%5B%5C%22font%5C%22%2C%7B%5C%22name%5C%22%3A%5C%22%E5%AE%8B%E4%BD%93%5C%22%2C%5C%22size%5C%22%3A%5C%2210%5C%22%2C%5C%22style%5C%22%3A%5B0%2C0%2C0%5D%2C%5C%22color%5C%22%3A%5C%22000000%5C%22%7D%5D%5D%22%2C%22msg_id%22%3A{$msg_id}%2C%22clientid%22%3A%22{$clientid}%22%2C%22psessionid%22%3A%22{$psessionid}%22%7D&clientid={$clientid}&psessionid={$psessionid}"
                #表情
                #postdata="r=%7B%22group_uin%22%3A{$group_uin}%2C%22content%22%3A%22%5B{$msg}%2C%5C%22%5C%5Cn%5C%22%2C%5B%5C%22font%5C%22%2C%7B%5C%22name%5C%22%3A%5C%22%E5%AE%8B%E4%BD%93%5C%22%2C%5C%22size%5C%22%3A%5C%2210%5C%22%2C%5C%22style%5C%22%3A%5B0%2C0%2C0%5D%2C%5C%22color%5C%22%3A%5C%22000000%5C%22%7D%5D%5D%22%2C%22msg_id%22%3A{$msg_id}%2C%22clientid%22%3A%22{$clientid}%22%2C%22psessionid%22%3A%22{$psessionid}%22%7D&clientid={$clientid}&psessionid={$psessionid}"
                #字符
                postdata="r=%7B%22group_uin%22%3A{$group_uin}%2C%22content%22%3A%22%5B{$msg}%2C%5C%22%5C%22%2C%5B%5C%22font%5C%22%2C%7B%5C%22name%5C%22%3A%5C%22%E5%AE%8B%E4%BD%93%5C%22%2C%5C%22size%5C%22%3A%5C%2210%5C%22%2C%5C%22style%5C%22%3A%5B0%2C0%2C0%5D%2C%5C%22color%5C%22%3A%5C%22000000%5C%22%7D%5D%5D%22%2C%22msg_id%22%3A{$msg_id}%2C%22clientid%22%3A%22{$clientid}%22%2C%22psessionid%22%3A%22{$psessionid}%22%7D&clientid={$clientid}&psessionid={$psessionid}"
                
                postdata=postdata.replace("{$group_uin}",str(groupid))
                postdata=postdata.replace("{$psessionid}",psessionid)
                postdata=postdata.replace("{$clientid}",str(self.clientid))
                postdata=postdata.replace("{$msg_id}",str(msg_id))
                postdata=postdata.replace("{$msg}",urlmsg)
                self.Post(url,postdata,QQRobot.HOST[0],QQRobot.REFERER[0],QQRobot.ORIGIN[0])
            except Exception,e:
                print "SendGroupMsg error"+str(e)
            #print "send msg: "+str(msg)

    心跳就是每隔一定时间向server请求一次 证明自己还在!
    #心跳包
        def HeartBreak(self,psessionid):
            url="http://d.web2.qq.com/channel/poll2"
            postdata="r=%7B%22clientid%22%3A%22{$clientid}%22%2C%22psessionid%22%3A%22{$psessionid}%22%2C%22key%22%3A0%2C%22ids%22%3A%5B%5D%7D&clientid={$clientid}&psessionid={$psessionid}"
            postdata=postdata.replace("{$clientid}",str(self.clientid))
            postdata=postdata.replace("{$psessionid}",psessionid)
            while True:
                #每隔2秒发送心跳包
                ret=self.Post(url,postdata,QQRobot.HOST[0],QQRobot.REFERER[0],QQRobot.ORIGIN[0])
                try:
                    retjson=json.loads(ret)
                    retjson=retjson["result"]
                    retjson=retjson[0]
                    #print "heartbreak"
                    if(retjson["poll_type"]=="group_message"):
                        msg=retjson["value"]
                        self.ProcessMsg(msg)
                except Exception,e:
                    #print "HeartBreak error "+str(e)
                    pass
                time.sleep(2)



    项目下载地址 http://download.csdn.net/detail/zhujunxxxxx/7663953

    明天继续更新。

    。。。。

     欢迎大家关注我的个人站点 http://www.zhujuncoding.com


     

  • 相关阅读:
    爬虫-某游戏交易网站商品信息爬取
    爬虫-淘宝selenium模拟登录取cookie
    设计模式
    xadmin安装2
    MySQL用户授权 和 bin-log日志 详解和实战
    用Redis实现分布式锁 与 实现任务队列
    基于H5的微信支付开发详解
    静态资源文件自动压缩并替换成压缩版本(大型网站优化技术)
    IP、TCP和DNS与HTTP的密切关系
    减少HTTP请求之将图片转成二进制并生成Base64编码,可以在网页中通过url查看图片(大型网站优化技术)
  • 原文地址:https://www.cnblogs.com/brucemengbm/p/6815020.html
Copyright © 2020-2023  润新知