不知道被谁删了微信好友?用 Python 来帮忙呀
生活随笔
收集整理的這篇文章主要介紹了
不知道被谁删了微信好友?用 Python 来帮忙呀
小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
本文根據(jù) gaosen 的開源項(xiàng)目?wechat-deleted-friends?整理而成。
還在苦惱不知道被誰刪了微信好友么?這里有個(gè) gaosen 編寫的工具可幫到你:
查看被刪的微信好友。原理就是新建群組,如果加不進(jìn)來就是被刪好友了(不要在群組里講話,別人是看不見的)。
用的是微信網(wǎng)頁版的接口。查詢結(jié)果可能會引起一些心理上的不適,請小心使用……[逃]
gaosen 說還有些小問題:
- 結(jié)果好像有疏漏一小部分,原因不明..
- 最終會遺留下一個(gè)只有自己的群組,需要手工刪一下
- 沒試過被拉黑的情況
Mac OS 用法:啟動終端
Shell| 1 | $ python wdf.py |
然后會彈出一個(gè)顯示登錄網(wǎng)頁版微信的二維碼窗口,用手機(jī)掃描登錄。按指示做即可!
不過大家要先把源代碼下載保存到 wdf.y 文件中。源碼源代碼在這里:
#!/usr/bin/env python # coding=utf-8 from __future__ import print_functionimport os try:from urllib import urlencode except ImportError:from urllib.parse import urlencodetry:import urllib2 as wdf_urllibfrom cookielib import CookieJar except ImportError:import urllib.request as wdf_urllibfrom http.cookiejar import CookieJarimport re import time import xml.dom.minidom import json import sys import math import subprocess import sslDEBUG = FalseMAX_GROUP_NUM = 35 # 每組人數(shù) INTERFACE_CALLING_INTERVAL = 16 # 接口調(diào)用時(shí)間間隔, 值設(shè)為13時(shí)親測出現(xiàn)"操作太頻繁" MAX_PROGRESS_LEN = 50QRImagePath = 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:xrangerange = xrange except:# python 3passdef getRequest(url, data=None):try:data = data.encode('utf-8')except:passfinally:return wdf_urllib.Request(url=url, data=data)def getUUID():global uuidurl = '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)if code == '200':return Truereturn Falsedef showQRImage():global tipurl = 'https://login.weixin.qq.com/qrcode/' + uuidparams = {'t': 'webwx','_': int(time.time()),}request = getRequest(url=url, data=urlencode(params))response = wdf_urllib.urlopen(request)tip = 1f = open(QRImagePath, 'wb')f.write(response.read())f.close()if sys.platform.find('darwin') >= 0:subprocess.call(['open', QRImagePath])elif sys.platform.find('linux') >= 0:subprocess.call(['xdg-open', QRImagePath])else:os.startfile(QRImagePath)print('請使用微信掃描二維碼以登錄')def waitForLogin():global tip, base_uri, redirect_uriurl = '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)if code == '201': # 已掃描print('成功掃描,請?jiān)谑謾C(jī)上點(diǎn)擊確認(rèn)以登錄')tip = 0elif code == '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('/')]# closeQRImageif sys.platform.find('darwin') >= 0: # for OSX with Previewos.system("osascript -e 'quit app \"Preview\"'")elif code == '408': # 超時(shí)pass# elif code == '400' or code == '500':return codedef login():global skey, wxsid, wxuin, pass_ticket, BaseRequestrequest = getRequest(url=redirect_uri)response = wdf_urllib.urlopen(request)data = response.read().decode('utf-8', 'replace')# print(data)'''<error><ret>0</ret><message>OK</message><skey>xxx</skey><wxsid>xxx</wxsid><wxuin>xxx</wxuin><pass_ticket>xxx</pass_ticket><isgrayscale>1</isgrayscale></error>'''doc = xml.dom.minidom.parseString(data)root = doc.documentElementfor node in root.childNodes:if node.nodeName == 'skey':skey = node.childNodes[0].dataelif node.nodeName == 'wxsid':wxsid = node.childNodes[0].dataelif node.nodeName == 'wxuin':wxuin = node.childNodes[0].dataelif node.nodeName == 'pass_ticket':pass_ticket = node.childNodes[0].data# print('skey: %s, wxsid: %s, wxuin: %s, pass_ticket: %s' % (skey, wxsid,# wxuin, pass_ticket))if not all((skey, wxsid, wxuin, pass_ticket)):return FalseBaseRequest = {'Uin': int(wxuin),'Sid': wxsid,'Skey': skey,'DeviceID': deviceId,}return Truedef webwxinit():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()if DEBUG:f = open(os.path.join(os.getcwd(), 'webwxinit.json'), 'wb')f.write(data)f.close()data = data.decode('utf-8', 'replace')# print(data)global ContactList, My, SyncKeydic = json.loads(data)ContactList = dic['ContactList']My = dic['User']SyncKeyList = []for item in dic['SyncKey']['List']:SyncKeyList.append('%s_%s' % (item['Key'], item['Val']))SyncKey = '|'.join(SyncKeyList)ErrMsg = dic['BaseResponse']['ErrMsg']if DEBUG:print("Ret: %d, ErrMsg: %s" % (dic['BaseResponse']['Ret'], ErrMsg))Ret = dic['BaseResponse']['Ret']if Ret != 0:return Falsereturn Truedef webwxgetcontact():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()if DEBUG: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']# 倒序遍歷,不然刪除的時(shí)候出問題..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"]for i in range(len(MemberList) - 1, -1, -1):Member = MemberList[i]if Member['VerifyFlag'] & 8 != 0: # 公眾號/服務(wù)號MemberList.remove(Member)elif Member['UserName'] in SpecialUsers: # 特殊賬號MemberList.remove(Member)elif Member['UserName'].find('@@') != -1: # 群聊MemberList.remove(Member)elif Member['UserName'] == My['UserName']: # 自己MemberList.remove(Member)return MemberListdef createChatroom(UserNames):# MemberList = []# for UserName in UserNames:# MemberList.append({'UserName': UserName})MemberList = [{'UserName': UserName} for UserName in UserNames]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 = []for Member in MemberList:if Member['MemberStatus'] == 4: # 被對方刪除了DeletedList.append(Member['UserName'])ErrMsg = dic['BaseResponse']['ErrMsg']if DEBUG:print("Ret: %d, ErrMsg: %s" % (dic['BaseResponse']['Ret'], ErrMsg))return ChatRoomName, DeletedListdef deleteMember(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']if DEBUG:print("Ret: %d, ErrMsg: %s" % (Ret, ErrMsg))if Ret != 0:return Falsereturn Truedef addMember(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 = []for Member in MemberList:if Member['MemberStatus'] == 4: # 被對方刪除了DeletedList.append(Member['UserName'])ErrMsg = dic['BaseResponse']['ErrMsg']if DEBUG:print("Ret: %d, ErrMsg: %s" % (dic['BaseResponse']['Ret'], ErrMsg))return DeletedListdef syncCheck():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"}def main():try:ssl._create_default_https_context = ssl._create_unverified_contextopener = wdf_urllib.build_opener(wdf_urllib.HTTPCookieProcessor(CookieJar()))wdf_urllib.install_opener(opener)except:passif not getUUID():print('獲取uuid失敗')returnshowQRImage()time.sleep(1)while waitForLogin() != '200':passos.remove(QRImagePath)if not login():print('登錄失敗')returnif not webwxinit():print('初始化失敗')returnMemberList = webwxgetcontact()MemberCount = len(MemberList)print('通訊錄共%s位好友' % MemberCount)ChatRoomName = ''result = []d = {}for Member in MemberList:d[Member['UserName']] = (Member['NickName'].encode('utf-8'), Member['RemarkName'].encode('utf-8'))print('開始查找...')group_num = int(math.ceil(MemberCount / float(MAX_GROUP_NUM)))for i in range(0, group_num):UserNames = []for j in range(0, MAX_GROUP_NUM):if i * MAX_GROUP_NUM + j >= MemberCount:breakMember = MemberList[i * MAX_GROUP_NUM + j]UserNames.append(Member['UserName'])# 新建群組/添加成員if ChatRoomName == '':(ChatRoomName, DeletedList) = createChatroom(UserNames)else:DeletedList = addMember(ChatRoomName, UserNames)DeletedCount = len(DeletedList)if DeletedCount > 0:result += DeletedList# 刪除成員deleteMember(ChatRoomName, UserNames)# 進(jìn)度條progress_len = MAX_PROGRESS_LENprogress = '-' * progress_lenprogress_str = '%s' % ''.join(map(lambda x: '#', progress[:(progress_len * (i + 1)) / group_num]))print(''.join(['[', progress_str, ''.join('-' * (progress_len - len(progress_str))), ']']))print('新發(fā)現(xiàn)你被%d人刪除' % DeletedCount)for i in range(DeletedCount):if d[DeletedList[i]][1] != '':print(d[DeletedList[i]][0] + '(%s)' % d[DeletedList[i]][1])else:print(d[DeletedList[i]][0])if i != group_num - 1:print('正在繼續(xù)查找,請耐心等待...')# 下一次進(jìn)行接口調(diào)用需要等待的時(shí)間time.sleep(INTERFACE_CALLING_INTERVAL)# todo 刪除群組print('\n結(jié)果匯總完畢,20s后可重試...')resultNames = []for r in result:if d[r][1] != '':resultNames.append(d[r][0] + '(%s)' % d[r][1])else:resultNames.append(d[r][0])print('---------- 被刪除的好友列表(共%d人) ----------' % len(result))# 過濾emojiresultNames = map(lambda x: re.sub(r'<span.+/span>', '', x), resultNames)if len(resultNames):print('\n'.join(resultNames))else:print("無")print('---------------------------------------------')# windows下編碼問題修復(fù) # http://blog.csdn.net/heyuxuanzee/article/details/8442718class UnicodeStreamFilter:def __init__(self, target):self.target = targetself.encoding = 'utf-8'self.errors = 'replace'self.encode_to = self.target.encodingdef write(self, s):if type(s) == str:s = s.decode('utf-8')s = s.encode(self.encode_to, self.errors).decode(self.encode_to)self.target.write(s)if sys.stdout.encoding == 'cp936':sys.stdout = UnicodeStreamFilter(sys.stdout)if __name__ == '__main__':print('本程序的查詢結(jié)果可能會引起一些心理上的不適,請小心使用...')print('開始')main()print('結(jié)束')
from:?http://python.jobbole.com/84072/
?gaosen / 0x5e
總結(jié)
以上是生活随笔為你收集整理的不知道被谁删了微信好友?用 Python 来帮忙呀的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 七步精通Python机器学习
- 下一篇: 用 Python 和 OpenCV 检测