python实现QQ机器⼈(⾃⼰主动登录,获取消息,发送消息)
⼀次偶然的机会我看见了⼀个⾥的⼀个QQ号总是依据你所发的消息⾃⼰主动回复,当时⾮常感觉到奇妙。我知道能够模拟登录站点,没想到居然也能模拟登录QQ,⾸先⾃⼰
想到的就是怎样实现模拟登录PC端的QQ, 開始研究了下,发现QQ所发送的包都⾮常难理解。
于是就转到了⽹页版的QQ,由于在⽹页⾥能够捕获全部的请求从⽽更好的实现模拟功能!
⾸先第⼀步就是打开⽹页版的qq。打开浏览器的开发⼈员模式 这⾥能够监控全部的请求!
打开登录界⾯的的时候
会捕捉到⼀个GET请求
当中uin是你的QQ号
返回值是 ptui_checkVC('1','AAr4bdjMeh2hEa77PTuoHhqMTxbRqOp3','\x00\x00\x00\x00\x00\xa1\x92\x12');
当中1表⽰须要验证码 另⼀种返回值 ptui_checkVC('0','!LJV','\x00\x00\x00\x00\x00\xa1\x92\x12') 这样的
表⽰是不须要的验证码的
会昌周田def CheckVerify(self,uin):
check="ssl.ptlogin2.qq/check?uin={uin}&appid=1003903&js_ver=10080&js_type=0&login_sig=YPD0P*wu2n8vW1OS2f7VfzvPf3Ku5vnkP4nzImF0GybR02fsKZdjGYB7f9R7nQRn&u1=http%3A%2F%2Fwe place('{uin}',uin)
pattern=repile("ptui_checkVC\('(.*)','(.*)','(.*)'\);")
result=self.Get(check)
checked= pattern.search(result).groups()
print 'Step1: CheckVerify'
return checked
获取验证码的⽅法
def GetVerify(self):
#url = 'ssl.captcha.qq/getimage?
&uin='+str(self.QQ)+'&aid=1002101&0.45644426648505' + str(random.randint(10,99)) verify="ssl.captcha.qq/getimage?
aid=1003903&r=0.6472875226754695&uin={QQ}&cap_cd=aSD-ZVcNEcozlZUurhNYhp-MBHf4hjbJ" place('{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.ad())
localPic.close() data.close()
输⼊username和password 还有验证码后发送⼀个GET请求
u=10588690&p=AB80CD3B6429D9660878E93058DD78BD&verifycode=TEYX&webqq_type=10&remember_uin=1&login2qq=1&aid=1003903&u1=http%
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'\x00\x00\x00\x00\x00\xa1\x92\x12')
loginurl="ssl.ptlogin2.qq/login?
u={uin}&p={pwd}&verifycode=
{verify}&webqq_type=10&remember_uin=1&login2qq=1&aid=1003903&u1=http%3A%2F%2Fweb2.qq%2Floginproxy.html%3Flogin2qq%3D1%26webqq_type%3D10&h=1 30-
135914&mibao_css=m_webqq&t=1&g=1&js_type=0&js_ver=10080&login_sig=YPD0P*wu2n8vW1OS2f7VfzvPf3Ku5vnkP4nzImF0GybR02fsKZdjGYB7f9R7nQRn&pt_uistyle= place('{uin}',uin) #place('{pwd}',pwd) #place('{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()
place('{verify}',code.upper()) pwd=self.PasswordSecret(pwd,r''+code.upper(),cheked[2])
#pwd=self.PasswordSecret(pwd,cheked[1],cheked[2]) else: place('{verify}',cheked[1]) pwd=self.PasswordSecret(pwd,cheked[1],cheked[2])
place('{pwd}',pwd) result=self.Get(loginurl,'ssl.ptlogin2.qq','ui.ptlogin2.qq/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%2Floginproxy.html&f_url=log
print 'Step2: Login' pattern=repile("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','ptlogin4.web2.qq/check_sig?
pttype=1&uin=10588690&service=login&nodirect=0&ptsig=*ZwU0pfTmYP93Fbdt6uSzbbODzlZ0EY9g25PDge5zZU_&s_url=http%3A%2F%2Fweb2.qq%2Floginproxy.htm 录成功!
', '⼩⽵');
第⼀个为0 就表⽰登录成功了 ,可是这并没有真正的登录成功
上⾯的返回值中的url是⽤来获取⼀个关键cookie的 那就是ptwebqq
然后进⾏第⼆次登录,这次才是真正的登录
请求例如以下
1.
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/; ts_refer=www.baidu/; 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
9. Origin:
d.web2.qq
10. Referer:
d.web2.qq/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
2. Form Data view source view 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="d.web2.qq/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%3A place("{$ptwebqq}",self.ptwebqq)
place("{$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":"8368046764001d636f6e6e7365727665725f77656271714031302e3133392e372e31363000006cb000001ae1036200a192126d0000000a40356c5937 "user_state":0,
清华投毒"f":0
}
}'''
这种数据结构 当中0表⽰登陆成功
须要把这写数据保存下来 后⾯进⾏操作须要
登陆成功后我们就能够拉去列表了
#获取列表信息
def GetGroupNameList(self,vfwebqq):
try:
url="s.web2.qq/api/get_group_name_list_mask2"
postdata="r=%7B%22vfwebqq%22%3A%22{$vfwebqq}%22%7D"
place("{$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"]
for group uplist['gnamelist']:
print group["code"],group["name"]
except Exception,e:
print "GetGroupNameList error"+str(e)
#获取成员信息
def GetGroupInfo(self,gcode,vfwebqq):
try:
url="s.web2.qq/api/get_group_info_ext2?gcode={$gcode}&cb=undefined&vfwebqq={$vfwebqq}&t=1402069438458"
place("{$vfwebqq}",vfwebqq)
place("{$gcode}",str(gcode))
ret=self.Get(url,QQRobot.HOST[1],QQRobot.REFERER[1],None)
qq消息print "Step6: GetGroupInfo"
retjson=json.loads(ret)
retjson=retjson["result"]
except Exception,e:
print "GetGroupInfo error"+str(e)
#发送消息
def SendGroupMsg(self,groupid,msg,psessionid):
try:
#msg=u">:"+msg
#msg=msg.strip()
#urlmsg=de('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"
#place("%20","")
place("%27","%5C%22") #把 ' 换为 \"
place("u","") #把 u 换为空
temp+=part
else:
temp+=place("{content}",de('utf8')))+"%2C"
temp=temp[0:len(temp)-3]
#urlmsg="%5C%228%5C%22"#"%5B%5C%22face%5C%22%2C13%5D"
urlmsg=temp
url="d.web2.qq/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%5 #表情
#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% #字符抄税
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
place("{$group_uin}",str(groupid))
place("{$psessionid}",psessionid)
place("{$clientid}",str(self.clientid))
place("{$msg_id}",str(msg_id))
place("{$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="d.web2.qq/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}" place("{$clientid}",str(self.clientid))
place("{$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)
明天继续更新。
。。。。
。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论