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="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'\x00\x00\x00\x00\x00\xa1\x92\x12')
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®master=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
请求例如以下
- Accept:*/*
- Accept-Encoding:gzip,deflate,sdch
- Accept-Language:zh-CN,zh;q=0.8
- Connection:keep-alive
- Content-Length:244
- Content-Type:application/x-www-form-urlencoded
- 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__ - Host:d.web2.qq.com
- Origin:http://d.web2.qq.com
- Referer:http://d.web2.qq.com/proxy.html?v=20110331002&callback=1&id=2
- User-Agent:Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/34.0.1847.116 Safari/537.36
- Form Dataview sourceview
URL encoded- r:{"status":"online","ptwebqq":"b21232ed3519839063d1c2ead8a8588c385d168097efdf88bc56e1a78be7dfb4","passwd_sig":"","clientid":"7963288","psessionid":null}
- clientid:7963288
- 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
python实现QQ机器人(自己主动登录,获取群消息,发送群消息)的更多相关文章
- python实现qq机器人qqbot
title: python实现qq机器人qqbot tags: python date: 2018-6-1 10:19:00 --- 以下内容为转载 一.介绍 qqbot 是一个用 python 实现 ...
- 第一讲 从头开始做一个web qq 机器人,第一步获取smart qq二维码
新手教程: 前言:最近在看了一下很久很久以前做的qq机器人失效了,最近也在换工作目前还在职,时间很挺宽裕的.就决定从新搞一个web qq机器人 PC的协议解析出来有点费时间以后再做. 准备工作: 编译 ...
- 「拆小鹤」使用 python 实现 QQ机器人服务。
使用的是python的qqbot机器人库,我其实只是实现了这个库的一个插件. 具体的说明,我觉得qqbot的官方文档,还有我的插件的注释都写得很详细了,可以直接看.所以有空再写吧. 没错我就是懒..
- NoneBot+酷Q,打造QQ机器人
NoneBot 是一个基于 酷Q 的 Python 异步 QQ 机器人框架,它会对 QQ 机器人收到的消息进行解析和处理,并以插件化的形式,分发给消息所对应的命令处理器和自然语言处理器,来完成具体的功 ...
- Android之QQ授权登录获取用户信息
有时候我们开发的app须要方便用户简单登录.能够让用户使用自己的qq.微信.微博登录到我们自己开发的app. 今天就在这里总结一下怎样在自己的app中集成QQ授权登录获取用户信息的功能. 首先我们打开 ...
- Python+mirai开发QQ机器人起步教程(2021.9.9测试有效)
参考:开发 mirai QQ机器人起步教程_叹之-CSDN博客_mirai python 本篇文章参考了以上博客,并对其中的失效内容和版本匹配问题进行了补充修改,实测能够成功运行.部分步骤的运行截图见 ...
- Python爬虫实战五之模拟登录淘宝并获取所有订单
经过多次尝试,模拟登录淘宝终于成功了,实在是不容易,淘宝的登录加密和验证太复杂了,煞费苦心,在此写出来和大家一起分享,希望大家支持. 温馨提示 更新时间,2016-02-01,现在淘宝换成了滑块验证了 ...
- 实现QQ机器人报警
如题,废话不说,直接上代码.首先是登录QQ的小脚本 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 ...
- Python3.x爬虫教程:爬网页、爬图片、自己主动登录
林炳文Evankaka原创作品. 转载请注明出处http://blog.csdn.net/evankaka 摘要:本文将使用Python3.4爬网页.爬图片.自己主动登录.并对HTTP协议做了一个简单 ...
随机推荐
- I2C驱动框架(四)
参考:I2C子系统之platform_driver初始化——I2C_adap_s3c_init() 在完成platform_device的添加之后,i2c子系统将进行platform_driver的注 ...
- Verilog学习笔记基本语法篇(一)·········数据类型
Verilog中共有19种数据类型. 基本的四种类型: reg型.wire型.integer型.parameter型. 其他类型:large型.medium型.small型.scalared型.tim ...
- angularJS $scope的$apply方法实现model刷新
控制器内,$scope有个$apply方法,可以代码更改model并同步更新页面.通常,控制器内的方法执行完毕后仅会自动刷新一次页面展示,使用$apply方法即可在想刷新页面时就刷新.如本例,这个方法 ...
- python基础-面向对象(装饰器)
属性: @property @method_name.setter @method_name.deleter 三个标签都是放在方法的上面来使用,且方法名要和后续使用的 变量名字相一 ...
- OmniGraffler软件和激活码
mac上用户画图的软件:OmniGraffler破解方法 1.激活码 Name: Appked SN: MFWG-GHEB-HYTW-CGHT-CSXU-QCNC-SXU 2.软件连接 链接: htt ...
- OSPF 提升四 Network Types & FRAM-RELAY
Network Types 1.loopback 2.point-to-point 3.broadcast 4.NBMA 5.POINT-TO-Multipoint 6.point-To-Multip ...
- 【LeetCode】Remove Nth Node From End of List(删除链表的倒数第N个节点)
这道题是LeetCode里的第19道题. 题目要求: 给定一个链表,删除链表的倒数第 n 个节点,并且返回链表的头结点. 示例: 给定一个链表: 1->2->3->4->5, ...
- CF802D
D. Marmots (easy) time limit per test 2 seconds memory limit per test 256 megabytes input standard i ...
- ICMP TYPE CODE
TYPE CODE Description Query Error 0 0 Echo Reply——回显应答(Ping应答) x 3 0 Network Unreachable——网络不可达 ...
- 【Luogu】P1854花店橱窗布置(DP)
照例良心题目链接 此题使用f[i][j]表示前i束花放进前j个花瓶的时候的最大值.转移方程如下 f[i][j]=max(f[i][j-1],f[i-1][j-1]+que[i][j]) 其中que[i ...