16 Star 33 Fork 2

毒菇 / pyqq

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
该仓库未声明开源许可证文件(LICENSE),使用请关注具体项目描述及其代码上游依赖。
克隆/下载
pyqq.py 23.86 KB
一键复制 编辑 原始数据 按行查看 历史
# -*- coding: UTF-8 -*-
import urllib
import urllib2
import cookielib
import re
import json, sys, os
import random,time,datetime
import threading
import pickle
#解决写入中文报错问题
reload(sys)
sys.setdefaultencoding('utf-8')
class RedirctHandler(urllib2.HTTPRedirectHandler):
def http_error_301(self, req, fp, code, msg, headers):
global new_location
new_location=headers['location']
pass
def http_error_302(self, req, fp, code, msg, headers):
global new_location
new_location=headers['location']
pass
class PyQQ:
ExploereHEADERS = {
"Accept":"*/*",
"Accept-Encoding":"gzip,deflate,sdch",
"Accept-Language":"zh-CN,zh;q=0.8,en;q=0.6",
"Content-type": "application/x-www-form-urlencoded",
'Accept-Language':'zh-CN,zh;q=0.8',
'User-Agent': 'Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.1916.114',
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
"Connection": "keep-alive",
"Cache-Control": "no-cache",
"Referer":"http://d.web2.qq.com/proxy.html?v=20130916001&callback=1&id=2",
}
#设置cookie
cj = cookielib.CookieJar()
opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(cj))
# 安装cookie
urllib2.install_opener(opener)
def GetWeb(self, url, method = 'get', values = ''):
if method == 'get':
req = urllib2.Request(url, headers = self.ExploereHEADERS)
else:
req = urllib2.Request(url,values,headers = self.ExploereHEADERS)
try:
response = urllib2.urlopen(req)
the_page = response.read()
response.close() #不用了就关闭掉
except:
the_page=''
return the_page
def __init__(self, qqnum = None, pwd = None):
print "Begin!"
if qqnum and pwd:
self.login(qqnum, pwd)
def login(self, qqnum, pwd):
if type(qqnum) == type(0):
qqnum = str(qqnum)
req = urllib2.Request('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=20150211001')
resp = urllib2.urlopen(req)
html = resp.read()
resp.close()
g_login_sig = re.compile("g_login_sig=encodeURIComponent\\(\"(.*?)\"\\);").findall(html)[0]
web = self.GetWeb('https://ssl.ptlogin2.qq.com/check?pt_tea=1&uin=' + qqnum + '&appid=1003903&js_ver=10116&js_type=0&login_sig=' + g_login_sig + '&u1=http%3A%2F%2Fweb2.qq.com%2Floginproxy.html&r=0.27641687798313797')
if web=='':
print '网络异常'.decode('utf-8')
sys.exit(1)
arr = re.compile("'(.*?)'").findall(web)
state = arr[0]
self.verifycode = arr[1]
uin = arr[2]
verifysession = arr[3]
self.uin = qqnum
self.pwd = pwd
if state == '1':
gif = self.GetWeb('http://captcha.qq.com/getimage?aid=1003903&r=0.45623475915069394&uin=' + self.uin)
file = open(os.getcwd()+'\qq' + qqnum +'code.bmp','w+b')
file.write(gif)
file.close()
#self.verifycode = raw_input('[' + qqnum + "] Please inpit the verifycode:")
data = urllib.urlencode({'image':gif,})
req=urllib2.Request('http://ckaqq.cn/code/?token='+self.get_token(), data)
resp = urllib2.urlopen(req)
qrcont=resp.read()
try:
result=json.loads(qrcont)
print "verifycode:"+result["res"]
self.verifycode=result["res"]
except:
self.verifycode=""
parameter = urllib.urlencode({'a': self.pwd, 'b': uin, 'c': self.verifycode})
req=urllib2.Request(nodeJsUrl + parameter)
resp = urllib2.urlopen(req)
p = resp.read()
#p = encrypt.encrypt(self.pwd, self.uin, self.verifycode)
#step one:第一次登陆
loginURL = 'https://ssl.ptlogin2.qq.com/login?u=' + self.uin + '&p=' + p + '&verifycode=' + self.verifycode + '&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=2-10-4498&mibao_css=m_webqq&t=1&g=1&js_type=0&js_ver=10116&login_sig='+ g_login_sig +'&pt_uistyle=5&pt_randsalt=0&pt_vcode_v1=0&pt_verifysession_v1=' + verifysession
login = self.GetWeb(loginURL)
info = re.compile("'(.*?)'").findall(login)
print 'User:[' + info[5].decode("utf-8") + '(' + self.uin + ')]' + info[4].decode("utf-8")
#成功是返回0
if info[0] != '0':
print random.choice(['What a pity!','Try again ~', 'Too weak to get the right verifycode!'])
sys.exit(1)
return "登陆失败"
#self.login(qqnum, pwd)
#上次因为这里的死循环被坑1块钱了,这里就不让无限尝试登陆了
#回调地址
loginURLback = info[2]
#print loginURLback
#step two:访问回调地址更新cookie
info = self.GetWeb(loginURLback)
#print info
for cookie in self.cj:
#print cookie.name,cookie.value
if cookie.name == 'ptwebqq':
self.ptwebqq = cookie.value
break
self.clientid = '51167527'
data = 'r=%7B%22ptwebqq%22%3A%22'+self.ptwebqq+'%22%2C%22clientid%22%3A51167527%2C%22psessionid%22%3A%22%22%2C%22 \
status%22%3A%22online%22%7D'
#step three:二次登陆
#{"retcode":103,"errmsg":""} {"retcode":121,"t":"0"} {"retcode":100006,"errmsg":""}
# 返回103、121,代表连接不成功,需要重新登录;
# 返回102,代表连接正常,此时服务器暂无信息;
# 返回0,代表服务器有信息传递过来:包括群信、群成员给你的发信,QQ好友给你的发信。
login2 = self.GetWeb('http://d.web2.qq.com/channel/login2', 'post', data)
#print login2
dic = eval(login2)
# print dic
self.vfwebqq = dic['result']['vfwebqq']
self.psessionid = dic['result']['psessionid']
def get_friendList(self):
#获取好友列表
getUserFriend = 'http://s.web2.qq.com/api/get_user_friends2'
#hash = encrypt.getHash2(self.uin, self.ptwebqq)
req = urllib2.Request(nodeJsUrl + 'b=' + self.uin + '&j=' + self.ptwebqq)
resp = urllib2.urlopen(req)
hash = resp.read()
resp.close()
#print hash
#data = 'r=%7B%22vfwebqq%22%3A%22'+self.vfwebqq+'%22%2C%22hash%22%3A%22'+hash+'%22%7D'
data = 'r=%7B%22h%22%3A%22hello%22%2C%22hash%22%3A%22' + hash + '%22%2C%22vfwebqq%22%3A%22' + self.vfwebqq + '%22%7D'
userfriend = self.GetWeb(getUserFriend,'post', data)
self.friends = json.loads(userfriend)['result']['info']
#根据uin 和 vfwebqq,得到真正的扣扣号account
for friend in self.friends:
print friend
uin = friend['uin']
data_get_account = 'http://s.web2.qq.com/api/get_friend_uin2?tuin='+str(uin)+'&type=1&vfwebqq='+self.vfwebqq+'&t=1405872226955'
friend_info = self.GetWeb(data_get_account)
friend_info = json.loads(friend_info)
account = friend_info['result']['account']
friend['account'] = account
print 'Get Friends list success!'
def get_groupList(self):
#Get group list
getGroup = 'http://s.web2.qq.com/api/get_group_name_list_mask2'
#hash = encrypt.getHash2(self.uin, self.ptwebqq)
req = urllib2.Request(nodeJsUrl + 'b=' + self.uin + '&j=' + self.ptwebqq)
resp = urllib2.urlopen(req)
hash = resp.read()
resp.close()
#print hash
data = 'r=%7B%22vfwebqq%22%3A%22'+self.vfwebqq+'%22%2C%22hash%22%3A%22'+hash+'%22%7D'
usergroup = self.GetWeb(getGroup,'post', data)
self.group = json.loads(usergroup)['result']['gnamelist']
for group in self.group:
print group
#由群信息获取真实群号
get_group_num = 'http://s.web2.qq.com/api/get_friend_uin2?' + 'tuin='+str(group['code'])+'&verifysession=&type=4&code=&vfwebqq=' + self.vfwebqq + '&t=1475202994632'
item = self.GetWeb(get_group_num)
item = json.loads(item)
group['account'] = item['result']['account']
#由群信息获取群成员信息
get_group_info = 'http://s.web2.qq.com/api/get_group_info_ext2?'+'gcode='+str(group['code'])+'&vfwebqq='+self.vfwebqq+'&t=1406197323657'
try:
group_info = self.GetWeb(get_group_info)
except:
print "Get Group info fail"
pass
result = json.loads(group_info)['result']
try:
members = result['minfo']
except:
#超级大群结构不同
members = result['ginfo']['members']
for member in members:
member['uin'] = member['muin']
member['nick'] = 'Null'
del member['muin']
#print members
group['members'] = members
print "Get Group info success!"
def getTime(self):
a = time.localtime(time.time())
b = time.strftime('%Y-%m-%d %H:%M:%S',a)
return b
def getMessageAll(self):
data = 'r=%7B%22clientid%22%3A%22' + self.clientid +\
'%22%2C%22psessionid%22%3A%22' + self.psessionid +\
'%22%2C%22key%22%3A0%2C%22ids%22%3A%5B%5D%7D&clientid=' + self.clientid +\
'&psessionid=' + self.psessionid
#print cj
rollURL = 'http://d.web2.qq.com/channel/poll2'
roll = self.GetWeb(rollURL,'post', data)
try:
message = json.loads(roll)['result']
except:
print 'roll: ' + roll
pass
msgs = []
for msg in message:
if msg['poll_type'] == u'message' or msg['poll_type'] == u'group_message':
msgs.append({'from':msg['value']['from_uin'], 'data':msg['value']['content'][1].strip(), 'type':msg['poll_type']})
return msgs
global global_uintoQQ_Dict
global global_uintoNick_Dict
global_uintoQQ_Dict = {}
global_uintoNick_Dict = {}
def analysisMsg(self,msg,friends,group,count=0):
if msg['poll_type'] == 'group_message':
gcode = msg['value']['group_code'] #gcode
gp_account = msg['value']['info_seq'] #real gp num
user_uin = str(msg['value']['send_uin']) #real send uin
try:
user_account = global_uintoQQ_Dict[user_uin]
nick = global_uintoNick_Dict[user_uin]
except:
user_account ='0'
flag=0
for gp in group:
if gp['code'] == gcode:
flag = 1
gp_name = gp['name'] #real qp name
if user_account == '0':
user_account,nick = self.get_memberQQ(user_uin,gp)
global_uintoQQ_Dict[user_uin] = user_account
global_uintoNick_Dict[user_uin] = nick
if flag == 0:
if count < 5:
self.get_groupList()
return self.analysisMsg(msg,self.friends,self.group,count+1)
else:
exit(1)
else:
return str(gp_account),gp_name,str(user_account),nick.encode('gbk','ignore').decode("gbk")
elif msg['poll_type'] == 'message':
#print msg
gp_account = '0'
gp_name = '0'
user_uin = msg['value']['from_uin']
flag = 0
for friend in friends:
if friend['uin'] == user_uin:
flag = 1
user_account = friend['account']
nick = friend['nick']
if flag == 0:
if count < 5:
self.get_friendList()
return self.analysisMsg(msg,self.friends,self.group,count+1)
else:
exit(1)
return str(gp_account),gp_name,str(user_account),nick
def get_memberQQ(self,user_uin,gp):
members = gp['members']
for member in members:
if str(member['uin']) == str(user_uin):
uin = member['uin']
uin_get_account = 'http://s.web2.qq.com/api/get_friend_uin2?tuin='+str(uin)+'&type=1&vfwebqq='+self.vfwebqq+'&t=1405872226955'
account = json.loads(self.GetWeb(uin_get_account))['result']['account']
member['account'] = str(account)
print "Group members:"+str(account)+' '+member['nick']
return str(account),member['nick']
# webQQ发送时不稳定不可靠的
# 消息发送不出去的常见原因:
#1、发送之后直接返回错误页面,说明参数,转码,COOKIES不对!
#2、返回0,一开始能发送出去,后来却又发送不去了,原因可能是程序采用单线程运作,
# 这种现象经常会出现,在我们发送消息的时候,需要一个线程去获取消息,即POLL。
# 简单来说,发送消息和接收消息需要两个独立的线程单独完成,不可将其合成一个线程里面。
# 再有就是"msg_id":23500002,看看是否累加1,前面的数字是随机数,后面的数字需要累加,
# 第1条消息就是1,第二条消息就是2。。。
def sendMessage(self, qqnum, content, method = "uin"):
if type(qqnum) in (type(u''), type('')):
qqnum = int(qqnum)
user=False
if method != 'uin': #通过发送到QQ号的方式发送消息
print "enter if"
for users in self.friends:
if users['account'] == qqnum:
user = users
break
else :
print "enter else"
for users in self.friends:
if users['uin'] == qqnum:
user = users
break
if not user:
return
#print user
if user.get('msgID') == None:
user['msgID'] = str(random.randint(10000000,99999999));
else :
msgID = int(user['msgID'])
msgID = msgID + 1
user['msgID'] = str(msgID)
msg = urllib.quote((str(content)))
#print msg
data ='r=%7B%22to%22%3A'+str(user['uin'])+'%2C%22content%22%3A%22%5B%5C%22'+msg+'%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%3A10%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%22face%22%3A'+str(user['face'])+'%2C%22clientid%22%3A'+self.clientid+'%2C%22msg_id%22%3A'+user['msgID']+'%2C%22psessionid%22%3A%22'+self.psessionid+'%22%7D'
sendURL = 'http://d.web2.qq.com/channel/send_buddy_msg2'
try:
send = self.GetWeb(sendURL, 'post', data)
except:
print 'I can say nothing!'
pass
print "Message [" + content.decode('utf-8') + "] send over!"
def sendGroupMessage(self, gid, content, method = "uin"):
if type(gid) in (type(u''), type('')):
gid = int(gid)
user = {}
if method != 'uin': #通过发送到QQ群号的方式发送消息
for gps in self.group:
if gps['account'] == gid:
user = gps
break
else :
for gps in self.group:
if gps['gid'] == gid:
user = gps
break
if not user:
return
#print user
if user.get('msgID') == None:
user['msgID'] = str(random.randint(10000000,99999999));
else :
msgID = int(user['msgID'])
msgID = msgID + 1
user['msgID'] = str(msgID)
msg = urllib.quote((str(content)).replace("\n","\\\\n").replace("\r","\\\\r"))
data = 'r=%7B%22group_uin%22%3A'+str(user['gid'])+'%2C%22content%22%3A%22%5B%5C%22'+msg+'%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%3A10%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%22faceface%22%3A0%2C%22clientid%22%3A'+self.clientid+'%2C%22msg_id%22%3A'+user['msgID']+'%2C%22psessionid%22%3A%22'+self.psessionid+'%22%7D'
sendURL = 'http://d.web2.qq.com/channel/send_qun_msg2'
try:
send = self.GetWeb(sendURL, 'post', data)
print send
except:
print 'I can say nothing...'
pass
print "Group Message[" + content + "] send over!"
def get_token(self):
import md5
hash1 = md5.new()
hash2 = md5.new()
nowtime = time.strftime("%Y-%m-%d-%H", time.localtime(time.time()))
hash1.update(nowtime)
hash2.update("csbxfd"+hash1.hexdigest())
return hash2.hexdigest()
def getMessage(self):
data = 'r=%7B%22ptwebqq%22%3A%22'+self.ptwebqq+'%22%2C%22clientid%22%3A'+self.clientid+'%2C%22psessionid%22%3A%22'+self.psessionid+'%22%2C%22key%22%3A%22%22%7D'
rollURL = 'http://d.web2.qq.com/channel/poll2'
roll = self.GetWeb(rollURL,'post', data)
print self.getTime()
#print roll
#f = open('1125.txt','a')
#f.write(roll)
#f.close()
try:
message = json.loads(roll)['result']
except:
message = 0
if not message:
return []
#可以一次接收多条消息,result是一个List
for msg in message:
if msg['poll_type'] == u'message' or msg['poll_type'] == u'group_message':
#print msg['value']['content']
print "message"
del msg['value']['content'][0]
msg['msgdata']=u""
for m in msg['value']['content']:
msg['msgdata']=msg['msgdata']+self.dealmsg(m,msg)
msg['msgdata']=msg['msgdata'].strip()
else:
if msg['poll_type'] == u'buddies_status_change':
print msg['value']["uin"],msg['value']["status"]
elif msg['poll_type'] == u'shake_message':
print msg['value']["from_uin"],"shake"
elif msg['poll_type'] == u"system_message":
rollURL = "http://s.web2.qq.com/api/allow_and_add2"
data = "r=%7b%22account%22%3a" + str(msg["value"]["account"]) + "%2c%22gid%22%3a0%2c%22mname%22%3a%22%22%2c%22vfwebqq%22%3a%22"+self.vfwebqq+"%22%7d"
roll = self.GetWeb(rollURL,'post', data)
print "add friend : "+str(msg["value"]["account"])
elif msg['poll_type'] == u"buddylist_change":
self.get_friendList()
print "update friends"
elif msg['poll_type'] == u"sys_g_msg":
print msg["value"]["type"]
else:
print self.getTime()
print roll
print "Other and System Message!"
message.remove(msg)
return message
def dealmsg(self,m,msg):
if type(m)==type(u''):
return m
if type(m)==type([]):
if m[0]==u'face':
return "![img](http://pub.idqqimg.com/lib/qqface/"+str(m[1])+".gif)"
elif m[0]==u'offpic':
rollURL = 'http://d.web2.qq.com/channel/get_offpic2?'+'file_path='+urllib.quote((str(m[1]['file_path'])))+'&f_uin='+str(msg['value']['from_uin'])+'&clientid='+self.clientid+'&psessionid='+self.psessionid
url = self.getimg(rollURL)
return "![img](" + url + ")"
elif m[0] == u'cface':
rollURL="http://web2.qq.com/cgi-bin/get_group_pic?type=0&gid="+str(msg['value']["group_code"])+"&uin="+str(msg['value']["send_uin"])+"&rip="+m[1]["server"].split(":")[0]+"&rport="+m[1]["server"].split(":")[1]+"&fid="+str(m[1]["file_id"])+"&pic="+m[1]["name"]+"&vfwebqq="+self.vfwebqq
url = self.getimg(rollURL)
return "![img](" + url + ")"
print m
return ""
def getimg(self,rollURL):
print "get image begin"
opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(self.cj),RedirctHandler)
urllib2.install_opener(opener)
self.GetWeb(rollURL)
opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(self.cj))
urllib2.install_opener(opener)
global new_location
print new_location
return new_location
class Get(threading.Thread):
def __init__(self, qq):
threading.Thread.__init__(self, name=qq)
self.qq = qq
self.thread_stop = False
def run(self):
i=0
while True:
if not self.thread_stop:
try:
msgs = self.qq.getMessage()
except:
msgs = []
if msgs == []:
print "No Text Message Accpeted! "+str(i)
i=i+1
pass
else:
for msg in msgs:
#try:
if True:
gp_account,gp_name,user_account,nick = self.qq.analysisMsg(msg,self.qq.friends,self.qq.group,0)
if not os.path.exists("msg"):
os.mkdir("msg")
post1 = {"gp_account":gp_account,
"gp_name":gp_name,
"user_account":user_account,
"nick":nick,
"msgdata":msg['msgdata'],
"time":datetime.datetime.now()}
Send(post1,qq).start()
#posts.insert(post1)
if gp_account!='0':
f = open(u'msg/qun'+'-'+gp_account+'.txt','a')
else:
f = open('msg/'+user_account+'.txt','a')
a = qq.getTime()+' '+nick.encode('gbk','ignore').decode("gbk")+'('+user_account+")"
b = msg['msgdata']
#print a,b
f.write(a+'\n'+b+'\n\n')
f.close()
#except:
if False:
print "Something Wrong in analysisMsg,try again!"
pass
else:
time.sleep(0.2)
def stop(self):
self.thread_stop = True
def restart(self):
self.thread_stop = False
class Send(threading.Thread):
def __init__(self, msgs, qq):
threading.Thread.__init__(self, name=qq)
self.qq = qq
self.msgs = msgs
def run(self):
#url = "http://2.aick.sinaapp.com/pyqq.php?token="+self.qq.get_token()+"&msg="+str(self.msgs['msgdata'])+"&qq="+str(self.msgs["user_account"])
#response = urllib2.urlopen(urllib2.Request(url))
#results = response.read()
#response.close()
results = self.msgs['msgdata']
self.qq.sendMessage(self.msgs["user_account"], results, "account")
if __name__ == '__main__':
qq = PyQQ()
nodeJsUrl = "http://127.0.0.1:8888/?"
account = raw_input('Please input QQ account :')
pwd= raw_input('Password:')
qq.login(account, pwd)
qq.get_friendList()
qq.get_groupList()
friends = qq.friends
groups = qq.group
getmsg = Get(qq)
getmsg.start()
print "Begin to get Messages!!!!!!!!!!!!!!!!!!!!"
qq.sendMessage(178803502,qq.getTime()+u" 成功运行","account")
Python
1
https://gitee.com/myck/pyqq.git
git@gitee.com:myck/pyqq.git
myck
pyqq
pyqq
master

搜索帮助