#!/usr/bin/env python
# coding=utf-8
from__future__importprint_function
importos
try:
fromurllibimporturlencode
exceptImportError:
fromurllib.parseimporturlencode
try:
importurllib2aswdf_urllib
fromcookielibimportCookieJar
exceptImportError:
importurllib.requestaswdf_urllib
fromhttp.cookiejarimportCookieJar
importre
importtime
importxml.dom.minidom
importjson
importsys
importmath
importsubprocess
importssl
DEBUG=False
MAX_GROUP_NUM=35# 每组人数
INTERFACE_CALLING_INTERVAL=16# 接口调用时间间隔, 值设为13时亲测出现"操作太频繁"
MAX_PROGRESS_LEN=50
QRImagePath=os.path.join(os.getcwd(),'qrcode.jpg')
tip=0
uuid=''
base_uri=''
redirect_uri=''
skey=''
wxsid=''
wxuin=''
pass_ticket=''
deviceId='e000000000000000'
BaseRequest={}
ContactList=[]
My=[]
SyncKey=''
try:
xrange
range=xrange
except:
# python 3
pass
defgetRequest(url,data=None):
try:
data=data.encode('utf-8')
except:
pass
finally:
returnwdf_urllib.Request(url=url,data=data)
defgetUUID():
globaluuid
url='https://login.weixin.qq.com/jslogin'
params={
'appid':'wx782c26e4c19acffb',
'fun':'new',
'lang':'zh_CN',
'_':int(time.time()),
}
request=getRequest(url=url,data=urlencode(params))
response=wdf_urllib.urlopen(request)
data=response.read().decode('utf-8','replace')
# print(data)
# window.QRLogin.code = 200; window.QRLogin.uuid = "oZwt_bFfRg==";
regx=r'window.QRLogin.code = (\d+); window.QRLogin.uuid = "(\S+?)"'
pm=re.search(regx,data)
code=pm.group(1)
uuid=pm.group(2)
ifcode=='200':
returnTrue
returnFalse
defshowQRImage():
globaltip
url='https://login.weixin.qq.com/qrcode/'+uuid
params={
't':'webwx',
'_':int(time.time()),
}
request=getRequest(url=url,data=urlencode(params))
response=wdf_urllib.urlopen(request)
tip=1
f=open(QRImagePath,'wb')
f.write(response.read())
f.close()
ifsys.platform.find('darwin')>=0:
subprocess.call(['open',QRImagePath])
elifsys.platform.find('linux')>=0:
subprocess.call(['xdg-open',QRImagePath])
else:
os.startfile(QRImagePath)
print('请使用微信扫描二维码以登录')
defwaitForLogin():
globaltip,base_uri,redirect_uri
url='https://login.weixin.qq.com/cgi-bin/mmwebwx-bin/login?tip=%s&uuid=%s&_=%s'%(
tip,uuid,int(time.time()))
request=getRequest(url=url)
response=wdf_urllib.urlopen(request)
data=response.read().decode('utf-8','replace')
# print(data)
# window.code=500;
regx=r'window.code=(\d+);'
pm=re.search(regx,data)
code=pm.group(1)
ifcode=='201':# 已扫描
print('成功扫描,请在手机上点击确认以登录')
tip=0
elifcode=='200':# 已登录
print('正在登录...')
regx=r'window.redirect_uri="(\S+?)";'
pm=re.search(regx,data)
redirect_uri=pm.group(1)+'&fun=new'
base_uri=redirect_uri[:redirect_uri.rfind('/')]
# closeQRImage
ifsys.platform.find('darwin')>=0:# for OSX with Preview
os.system("osa -e 'quit app \"Preview\"'")
elifcode=='408':# 超时
pass
# elif code == '400' or code == '500':
returncode
deflogin():
globalskey,wxsid,wxuin,pass_ticket,BaseRequest
request=getRequest(url=redirect_uri)
response=wdf_urllib.urlopen(request)
data=response.read().decode('utf-8','replace')
# print(data)
'''
0
OK
xxx
xxx
xxx
xxx
1
'''
doc=xml.dom.minidom.parseString(data)
root=doc.documentElement
fornodeinroot.childNodes:
ifnode.nodeName=='skey':
skey=node.childNodes[0].data
elifnode.nodeName=='wxsid':
wxsid=node.childNodes[0].data
elifnode.nodeName=='wxuin':
wxuin=node.childNodes[0].data
elifnode.nodeName=='pass_ticket':
pass_ticket=node.childNodes[0].data
# print('skey: %s, wxsid: %s, wxuin: %s, pass_ticket: %s' % (skey, wxsid,
# wxuin, pass_ticket))
ifnotall((skey,wxsid,wxuin,pass_ticket)):
returnFalse
BaseRequest={
'Uin':int(wxuin),
'Sid':wxsid,
'Skey':skey,
'DeviceID':deviceId,
}
returnTrue
defwebwxinit():
url=base_uri+\
'/webwxinit?pass_ticket=%s&skey=%s&r=%s'%(
pass_ticket,skey,int(time.time()))
params={
'BaseRequest':BaseRequest
}
request=getRequest(url=url,data=json.dumps(params))
request.add_header('ContentType','application/json; charset=UTF-8')
response=wdf_urllib.urlopen(request)
data=response.read()
ifDEBUG:
f=open(os.path.join(os.getcwd(),'webwxinit.json'),'wb')
f.write(data)
f.close()
data=data.decode('utf-8','replace')
# print(data)
globalContactList,My,SyncKey
dic=json.loads(data)
ContactList=dic['ContactList']
My=dic['User']
SyncKeyList=[]
foritemindic['SyncKey']['List']:
SyncKeyList.append('%s_%s'%(item['Key'],item['Val']))
SyncKey='|'.join(SyncKeyList)
ErrMsg=dic['BaseResponse']['ErrMsg']
ifDEBUG:
print("Ret: %d, ErrMsg: %s"%(dic['BaseResponse']['Ret'],ErrMsg))
Ret=dic['BaseResponse']['Ret']
ifRet!=0:
returnFalse
returnTrue
defwebwxgetcontact():
url=base_uri+\
'/webwxgetcontact?pass_ticket=%s&skey=%s&r=%s'%(
pass_ticket,skey,int(time.time()))
request=getRequest(url=url)
request.add_header('ContentType','application/json; charset=UTF-8')
response=wdf_urllib.urlopen(request)
data=response.read()
ifDEBUG:
f=open(os.path.join(os.getcwd(),'webwxgetcontact.json'),'wb')
f.write(data)
f.close()
# print(data)
data=data.decode('utf-8','replace')
dic=json.loads(data)
MemberList=dic['MemberList']
# 倒序遍历,不然删除的时候出问题..
SpecialUsers=["newsapp","fmessage","filehelper","weibo","qqmail","tmessage","qmessage","qqsync","floatbottle","lbsapp","shakeapp","medianote","qqfriend","readerapp","blogapp","facebookapp","masssendapp",
"meishiapp","feedsapp","voip","blogappweixin","weixin","brandsessionholder","weixinreminder","wxid_novlwrv3lqwv11","gh_22b87fa7cb3c","officialaccounts","notification_messages","wxitil","userexperience_alarm"]
foriinrange(len(MemberList)-1,-1,-1):
Member=MemberList[i]
ifMember['VerifyFlag']&8!=0:# 公众号/服务号
MemberList.remove(Member)
elifMember['UserName']inSpecialUsers:# 特殊账号
MemberList.remove(Member)
elifMember['UserName'].find('@@')!= -1:# 群聊
MemberList.remove(Member)
elifMember['UserName']==My['UserName']:# 自己
MemberList.remove(Member)
returnMemberList
defcreateChatroom(UserNames):
# MemberList = []
# for UserName in UserNames:
# MemberList.append({'UserName': UserName})
MemberList=[{'UserName':UserName}forUserNameinUserNames]
url=base_uri+\
'/webwxcreatechatroom?pass_ticket=%s&r=%s'%(
pass_ticket,int(time.time()))
params={
'BaseRequest':BaseRequest,
'MemberCount':len(MemberList),
'MemberList':MemberList,
'Topic':'',
}
request=getRequest(url=url,data=json.dumps(params))
request.add_header('ContentType','application/json; charset=UTF-8')
response=wdf_urllib.urlopen(request)
data=response.read().decode('utf-8','replace')
# print(data)
dic=json.loads(data)
ChatRoomName=dic['ChatRoomName']
MemberList=dic['MemberList']
DeletedList=[]
forMemberinMemberList:
ifMember['MemberStatus']==4:# 被对方删除了
DeletedList.append(Member['UserName'])
ErrMsg=dic['BaseResponse']['ErrMsg']
ifDEBUG:
print("Ret: %d, ErrMsg: %s"%(dic['BaseResponse']['Ret'],ErrMsg))
returnChatRoomName,DeletedList
defdeleteMember(ChatRoomName,UserNames):
url=base_uri+\
'/webwxupdatechatroom?fun=delmember&pass_ticket=%s'%(pass_ticket)
params={
'BaseRequest':BaseRequest,
'ChatRoomName':ChatRoomName,
'DelMemberList':','.join(UserNames),
}
request=getRequest(url=url,data=json.dumps(params))
request.add_header('ContentType','application/json; charset=UTF-8')
response=wdf_urllib.urlopen(request)
data=response.read().decode('utf-8','replace')
# print(data)
dic=json.loads(data)
ErrMsg=dic['BaseResponse']['ErrMsg']
Ret=dic['BaseResponse']['Ret']
ifDEBUG:
print("Ret: %d, ErrMsg: %s"%(Ret,ErrMsg))
ifRet!=0:
returnFalse
returnTrue
defaddMember(ChatRoomName,UserNames):
url=base_uri+\
'/webwxupdatechatroom?fun=addmember&pass_ticket=%s'%(pass_ticket)
params={
'BaseRequest':BaseRequest,
'ChatRoomName':ChatRoomName,
'AddMemberList':','.join(UserNames),
}
request=getRequest(url=url,data=json.dumps(params))
request.add_header('ContentType','application/json; charset=UTF-8')
response=wdf_urllib.urlopen(request)
data=response.read().decode('utf-8','replace')
# print(data)
dic=json.loads(data)
MemberList=dic['MemberList']
DeletedList=[]
forMemberinMemberList:
ifMember['MemberStatus']==4:# 被对方删除了
DeletedList.append(Member['UserName'])
ErrMsg=dic['BaseResponse']['ErrMsg']
ifDEBUG:
print("Ret: %d, ErrMsg: %s"%(dic['BaseResponse']['Ret'],ErrMsg))
returnDeletedList
defsyncCheck():
url=base_uri+'/synccheck?'
params={
'skey':BaseRequest['SKey'],
'sid':BaseRequest['Sid'],
'uin':BaseRequest['Uin'],
'deviceId':BaseRequest['DeviceID'],
'synckey':SyncKey,
'r':int(time.time()),
}
request=getRequest(url=url+urlencode(params))
response=wdf_urllib.urlopen(request)
data=response.read().decode('utf-8','replace')
# print(data)
# window.synccheck={retcode:"0",selector:"2"}
defmain():
try:
ssl._create_default_https_context=ssl._create_unverified_context
opener=wdf_urllib.build_opener(
wdf_urllib.HTTPCookieProcessor(CookieJar()))
wdf_urllib.install_opener(opener)
except:
pass
ifnotgetUUID():
print('获取uuid失败')
return
showQRImage()
time.sleep(1)
whilewaitForLogin()!='200':
pass
os.remove(QRImagePath)
ifnotlogin():
print('登录失败')
return
ifnotwebwxinit():
print('初始化失败')
return
MemberList=webwxgetcontact()
MemberCount=len(MemberList)
print('通讯录共%s位好友'%MemberCount)
ChatRoomName=''
result=[]
d={}
forMemberinMemberList:
d[Member['UserName']]=(Member['NickName'].encode(
'utf-8'),Member['RemarkName'].encode('utf-8'))
print('开始查找...')
group_num=int(math.ceil(MemberCount/float(MAX_GROUP_NUM)))
foriinrange(0,group_num):
UserNames=[]
forjinrange(0,MAX_GROUP_NUM):
ifi*MAX_GROUP_NUM+j>=MemberCount:
break
Member=MemberList[i*MAX_GROUP_NUM+j]
UserNames.append(Member['UserName'])
# 新建群组/添加成员
ifChatRoomName=='':
(ChatRoomName,DeletedList)=createChatroom(UserNames)
else:
DeletedList=addMember(ChatRoomName,UserNames)
DeletedCount=len(DeletedList)
ifDeletedCount>0:
result+=DeletedList
# 删除成员
deleteMember(ChatRoomName,UserNames)
# 进度条
progress_len=MAX_PROGRESS_LEN
progress='-'*progress_len
progress_str='%s'%''.join(
map(lambdax:'#',progress[:(progress_len*(i+1))/group_num]))
print(''.join(
['[',progress_str,''.join('-'*(progress_len-len(progress_str))),']']))
print('新发现你被%d人删除'%DeletedCount)
foriinrange(DeletedCount):
ifd[DeletedList[i]][1]!='':
print(d[DeletedList[i]][0]+'(%s)'%d[DeletedList[i]][1])
else:
print(d[DeletedList[i]][0])
ifi!=group_num-1:
print('正在继续查找,请耐心等待...')
# 下一次进行接口调用需要等待的时间
time.sleep(INTERFACE_CALLING_INTERVAL)
# todo 删除群组
print('\n结果汇总完毕,20s后可重试...')
resultNames=[]
forrinresult:
ifd[r][1]!='':
resultNames.append(d[r][0]+'(%s)'%d[r][1])
else:
resultNames.append(d[r][0])
print('---------- 被删除的好友列表(共%d人) ----------'%len(result))
# 过滤emoji
resultNames=map(lambdax:re.sub(r'','',x),resultNames)
iflen(resultNames):
print('\n'.join(resultNames))
else:
print("无")
print('---------------------------------------------')
# windows下编码问题修复
# http://blog.csdn.net/heyuxuanzee/article/details/8442718
classUnicodeStreamFilter:
def__init__(self,target):
self.target=target
self.encoding='utf-8'
self.errors='replace'
self.encode_to=self.target.encoding
defwrite(self,s):
iftype(s)==str:
s=s.decode('utf-8')
s=s.encode(self.encode_to,self.errors).decode(self.encode_to)
self.target.write(s)
ifsys.stdout.encoding=='cp936':
sys.stdout=UnicodeStreamFilter(sys.stdout)
if__name__=='__main__':
print('本程序的查询结果可能会引起一些心理上的不适,请小心使用...')
print('开始')
main()
print('结束')返回搜狐,查看更多