Created
November 21, 2011 01:40
-
-
Save saga/1381374 to your computer and use it in GitHub Desktop.
Python实现QQ机器人
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
目前网上有不少的实现QQ机器人的方法,都不太稳定甚至都已经失效了,而且我们还要冒着QQ号被盗用的风险。其实我们可以自己实现一个QQ自动应答的机器人,思路非常简单:通过模拟登录3G版QQ,来实现相关的操作: | |
一、首先我们得看看3GQQ的相关协议 | |
为此,我们需要一个支持WAP的浏览器,可以使用Firefox的wmlbrowser插件,打开FF后,访问地址:https://addons.mozilla.org/zh-CN/firefox/search/?q=wmlbrowser&cat=all&x=17&y=11 | |
二、进入3GQQ的进行协议分析 | |
3GQQ的地址是:http://pt.3g.qq.com/s?aid=nLogin3gqq 用安装了wmlbrowser插件的FF打开页面后,启用firebug,即可监视提交的数据。 | |
三、源代码 | |
以下源代码只实现了登陆和收发消息,如果需要更多的功能,可通过上面的方法自己监视协议即可,若你开发了更多的功能,可留言告诉我,一起完善该程序: | |
*注:代码中的HTTP请求写了2个版本的,若要采用pycurl的版本,请到http://www.lfd.uci.edu/~gohlke/pythonlibs/下载对应的pycurl库。 | |
#coding:utf-8 | |
#基于python2.6版本开发 | |
import httplib,urllib,os,threading,re | |
import sys | |
reload(sys) | |
sys.setdefaultencoding('utf8') | |
class PYQQ: | |
def __init__(self): | |
self.reqIndex = 0 | |
#HTTP请求 | |
def httpRequest(self,method,url,data={}): | |
try: | |
_urld = httplib.urlsplit(url) | |
conn = httplib.HTTPConnection(_urld.netloc,80,True,3) | |
conn.connect() | |
data = urllib.urlencode(data) | |
if method=='get': | |
conn.putrequest("GET", url, None) | |
conn.putheader("Content-Length",'0') | |
elif method=='post': | |
conn.putrequest("POST", url) | |
conn.putheader("Content-Length", str(len(data))) | |
conn.putheader("Content-Type", "application/x-www-form-urlencoded") | |
conn.putheader("Connection", "close") | |
conn.endheaders() | |
if len(data)>0: | |
conn.send(data) | |
f = conn.getresponse() | |
self.httpBody = f.read().encode('gbk') | |
f.close() | |
conn.close() | |
except: | |
self.httpBody='' | |
return self.httpBody | |
#HTTP请求的pycurl版本,和上面的程序选一即可 | |
def httpRequest_(self,method,url,data={}): | |
import pycurl,StringIO | |
c = pycurl.Curl() | |
c.setopt(pycurl.URL,url) | |
if method=='post': | |
import urllib | |
c.setopt(c.POSTFIELDS, urllib.urlencode(data)) | |
c.fp = StringIO.StringIO() | |
c.setopt(pycurl.WRITEFUNCTION,c.fp.write) | |
c.perform() | |
self.httpBody = c.fp.getvalue().encode('gbk') | |
del c.fp | |
c.close() | |
c = None | |
return self.httpBody | |
#通过首尾获取字符串的内容 | |
def getCon(self,start,end): | |
findex = self.httpBody.find(start) | |
if findex == -1 : return None | |
tmp = self.httpBody.split(start) | |
eindex = tmp[1].find(end) | |
if eindex == -1: | |
return tmp[1][0:] | |
else: | |
return tmp[1][0:eindex] | |
#获取postfield的值 | |
def getField(self,fd): | |
KeyStart = '<postfield name="'+ str(fd) +'" value="' | |
return self.getCon(KeyStart,'"/>') | |
#获取登陆验证码,并保存至当前目录的qqcode.gif | |
def getSafecode(self): | |
url = self.getCon('<img src="','"') | |
import urllib2 | |
pager = urllib2.urlopen(url) | |
data=pager.read() | |
file=open(os.getcwd()+'\qqcode.gif','w+b') | |
file.write(data) | |
file.close() | |
return True | |
#登陆QQ | |
def login(self): | |
self.qq = raw_input('请输入QQ号:') | |
self.pwd = raw_input('请输入密码:') | |
s1Back = self.httpRequest('post','http://pt.3g.qq.com/handleLogin',{'r':'324525157','qq':self.qq,'pwd':self.pwd,'toQQchat':'true','q_from':'','modifySKey':0,'loginType':1}) | |
if s1Back.find('请输入验证码')!=-1: | |
self.sid = self.getField('sid') | |
self.hexpwd = self.getField('hexpwd') | |
self.extend = self.getField('extend') | |
self.r_sid = self.getField('r_sid') | |
self.rip = self.getField('rip') | |
if self.getSafecode(): | |
self.safeCode = raw_input('请输入验证码(本文件同目录的qqcode.gif):') | |
else: | |
print '验证码加载错误' | |
postData = {'sid':self.sid,'qq':self.qq,'hexpwd':self.hexpwd,'hexp':'true','auto':'0', | |
'logintitle':'手机腾讯网','q_from':'','modifySKey':'0','q_status':'10', | |
'r':'271','loginType':'1','prev_url':'10','extend':self.extend,'r_sid':self.r_sid, | |
'bid_code':'','bid':'-1','toQQchat':'true','rip':self.rip,'verify':self.safeCode, | |
} | |
s1Back = self.httpRequest('post','http://pt.3g.qq.com/handleLogin',postData) | |
self.sid = self.getCon('sid=','&') | |
print '登陆成功' | |
self.getMsgFun() | |
#定时获取消息 | |
def getMsgFun(self): | |
self.reqIndex = self.reqIndex + 1 | |
s2Back = self.httpRequest('get','http://q32.3g.qq.com/g/s?aid=nqqchatMain&sid='+self.sid) | |
if s2Back.find('alt="聊天"/>(')!=-1: | |
#有新消息,请求获取消息页面 | |
s3back = self.httpRequest('get','http://q32.3g.qq.com/g/s?sid='+ self.sid + '&aid=nqqChat&saveURL=0&r=1310115753&g_f=1653&on=1') | |
#消息发起者的昵称 | |
if s3back.find('title="临时会话')!=-1: | |
_fromName = '临时对话' | |
else: | |
_fromName = self.getCon('title="与','聊天') | |
#消息发起者的QQ号 | |
_fromQQ = self.getCon('num" value="','"/>') | |
#消息内容 | |
_msg_tmp = self.getCon('saveURL=0">提示</a>)','<input name="msg"') | |
crlf = '\n' | |
if _msg_tmp.find('\r\n')!=-1: crlf = '\r\n' | |
_msg = re.findall(r'(.+)<br/>'+ crlf +'(.+)<br/>',_msg_tmp) | |
for _data in _msg: | |
self.getMsg({'qq':_fromQQ,'nick':_fromName,'time':_data[0],'msg':str(_data[1]).strip()}) | |
if self.reqIndex>=30: | |
#保持在线 | |
_url = 'http://pt5.3g.qq.com/s?aid=nLogin3gqqbysid&3gqqsid='+self.sid | |
self.httpRequest('get',_url) | |
self.reqIndex = 0 | |
t = threading.Timer(2.0,self.getMsgFun) | |
t.start() | |
#发送消息 | |
#qq 目标QQ | |
#msg 发送内容 | |
def sendMsgFun(self,qq,msg): | |
msg = unicode(msg,'gbk').encode('utf8') | |
postData = {'sid':self.sid,'on':'1','saveURL':'0','saveURL':'0','u':qq,'msg':str(msg),} | |
s1Back = self.httpRequest('post','http://q16.3g.qq.com/g/s?sid='+ self.sid +'&aid=sendmsg&tfor=qq',postData) | |
print '发送消息给',qq,'成功' | |
#收到消息的接口,重载或重写该方法 | |
def getMsg(self,data): | |
print data['time'],"收到",data['nick'],"(",data['qq'],")的新消息" | |
self.sendMsgFun(data['qq'],data['nick']+',我收到了你的消息:'+ data['msg']) | |
QQ = PYQQ() | |
QQ.login() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment