微信 用脚本查看是否被微信好友删除


Posted in Python onOctober 28, 2016

微信 用脚本查看是否被微信好友删除

某日,一同学给小的发了 Github 源码,说是可以轻松查到删除自己的微信好友,于是就开始了作死之路。

Github 源码请看:0x5e/wechat-deleted-friends

前言

相信各位一定有收到过这样的群发短信,据说还被归类为玩转微信的五大技巧之一?(???)?但,其实,只要跑一下脚本,就轻松找出删除自己的好友(轻松摔碎玻璃心,逃

GitHub:开源怪我咯?

原理

新建群组,如果加不进来就是被删好友了(不要在群组里讲话,别人是看不见的)。

用的是微信网页版的接口,还有些小问题,不过现在结果好像有疏漏一小部分,原因不明……也没试过被拉黑的情况。最终会遗留下一个只有自己的群组,需要手工删一下。

方法

下载 python 脚本,跑一下。启动 Terminal,切到文件目录下:

python wdf.py

代码如下

#!/usr/bin/env python
# coding=utf-8

import os
import urllib, urllib2
import re
import cookielib
import time
import xml.dom.minidom
import json
import sys
import math

DEBUG = False

MAX_GROUP_NUM = 35 # 每组人数

QRImagePath = os.getcwd() + '/qrcode.jpg'

tip = 0
uuid = ''

base_uri = ''
redirect_uri = ''

skey = ''
wxsid = ''
wxuin = ''
pass_ticket = ''
deviceId = 'e000000000000000'

BaseRequest = {}

ContactList = []
My = []

def getUUID():
  global uuid

  url = 'https://login.weixin.qq.com/jslogin'
  params = {
    'appid': 'wx782c26e4c19acffb',
    'fun': 'new',
    'lang': 'zh_CN',
    '_': int(time.time()),
  }

  request = urllib2.Request(url = url, data = urllib.urlencode(params))
  response = urllib2.urlopen(request)
  data = response.read()

  # 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 True

  return False

def showQRImage():
  global tip

  url = 'https://login.weixin.qq.com/qrcode/' + uuid
  params = {
    't': 'webwx',
    '_': int(time.time()),
  }

  request = urllib2.Request(url = url, data = urllib.urlencode(params))
  response = urllib2.urlopen(request)

  tip = 1

  f = open(QRImagePath, 'wb')
  f.write(response.read())
  f.close()

  if sys.platform.find('darwin') >= 0:
    os.system('open %s' % QRImagePath)
  elif sys.platform.find('linux') >= 0:
    os.system('xdg-open %s' % QRImagePath)
  else:
    os.system('call %s' % QRImagePath)

  print '请使用微信扫描二维码以登录'

def waitForLogin():
  global tip, 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 = urllib2.Request(url = url)
  response = urllib2.urlopen(request)
  data = response.read()
  
  # print data

  # window.code=500;
  regx = r'window.code=(\d+);'
  pm = re.search(regx, data)

  code = pm.group(1)

  if code == '201': #已扫描
    print '成功扫描,请在手机上点击确认以登录'
    tip = 0
  elif 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('/')]
  elif code == '408': #超时
    pass
  # elif code == '400' or code == '500':

  return code

def login():
  global skey, wxsid, wxuin, pass_ticket, BaseRequest

  request = urllib2.Request(url = redirect_uri)
  response = urllib2.urlopen(request)
  data = response.read()

  # 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.documentElement

  for node in root.childNodes:
    if node.nodeName == 'skey':
      skey = node.childNodes[0].data
    elif node.nodeName == 'wxsid':
      wxsid = node.childNodes[0].data
    elif node.nodeName == 'wxuin':
      wxuin = node.childNodes[0].data
    elif 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 skey == '' or wxsid == '' or wxuin == '' or pass_ticket == '':
    return False

  BaseRequest = {
    'Uin': int(wxuin),
    'Sid': wxsid,
    'Skey': skey,
    'DeviceID': deviceId,
  }

  return True

def webwxinit():

  url = base_uri + '/webwxinit?pass_ticket=%s&skey=%s&r=%s' % (pass_ticket, skey, int(time.time()))
  params = {
    'BaseRequest': BaseRequest
  }

  request = urllib2.Request(url = url, data = json.dumps(params))
  request.add_header('ContentType', 'application/json; charset=UTF-8')
  response = urllib2.urlopen(request)
  data = response.read()

  if DEBUG == True:
    f = open(os.getcwd() + '/webwxinit.json', 'wb')
    f.write(data)
    f.close()

  # print data

  global ContactList, My
  dic = json.loads(data)
  ContactList = dic['ContactList']
  My = dic['User']

  ErrMsg = dic['BaseResponse']['ErrMsg']
  if len(ErrMsg) > 0:
    print ErrMsg

  Ret = dic['BaseResponse']['Ret']
  if Ret != 0:
    return False
    
  return True

def webwxgetcontact():
  
  url = base_uri + '/webwxgetcontact?pass_ticket=%s&skey=%s&r=%s' % (pass_ticket, skey, int(time.time()))

  request = urllib2.Request(url = url)
  request.add_header('ContentType', 'application/json; charset=UTF-8')
  response = urllib2.urlopen(request)
  data = response.read()

  if DEBUG == True:
    f = open(os.getcwd() + '/webwxgetcontact.json', 'wb')
    f.write(data)
    f.close()

  # print data

  dic = json.loads(data)
  MemberList = dic['MemberList']

  # 倒序遍历,不然删除的时候出问题..
  SpecialUsers = ['newsapp', 'fmessage', 'filehelper', 'weibo', 'qqmail', 'fmessage', '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', 'wxid_novlwrv3lqwv11', 'gh_22b87fa7cb3c', 'wxitil', 'userexperience_alarm', 'notification_messages']
  for i in xrange(len(MemberList) - 1, -1, -1):
    Member = MemberList[i]
    if Member['VerifyFlag'] & 8 != 0: # 公众号/服务号
      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 MemberList

def createChatroom(UserNames):
  MemberList = []
  for UserName in UserNames:
    MemberList.append({'UserName': UserName})


  url = base_uri + '/webwxcreatechatroom?pass_ticket=%s&r=%s' % (pass_ticket, int(time.time()))
  params = {
    'BaseRequest': BaseRequest,
    'MemberCount': len(MemberList),
    'MemberList': MemberList,
    'Topic': '',
  }

  request = urllib2.Request(url = url, data = json.dumps(params))
  request.add_header('ContentType', 'application/json; charset=UTF-8')
  response = urllib2.urlopen(request)
  data = response.read()

  # 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 len(ErrMsg) > 0:
    print ErrMsg

  return (ChatRoomName, DeletedList)

def deleteMember(ChatRoomName, UserNames):
  url = base_uri + '/webwxupdatechatroom?fun=delmember&pass_ticket=%s' % (pass_ticket)
  params = {
    'BaseRequest': BaseRequest,
    'ChatRoomName': ChatRoomName,
    'DelMemberList': ','.join(UserNames),
  }

  request = urllib2.Request(url = url, data = json.dumps(params))
  request.add_header('ContentType', 'application/json; charset=UTF-8')
  response = urllib2.urlopen(request)
  data = response.read()

  # print data

  dic = json.loads(data)
  ErrMsg = dic['BaseResponse']['ErrMsg']
  if len(ErrMsg) > 0:
    print ErrMsg

  Ret = dic['BaseResponse']['Ret']
  if Ret != 0:
    return False
    
  return True

def addMember(ChatRoomName, UserNames):
  url = base_uri + '/webwxupdatechatroom?fun=addmember&pass_ticket=%s' % (pass_ticket)
  params = {
    'BaseRequest': BaseRequest,
    'ChatRoomName': ChatRoomName,
    'AddMemberList': ','.join(UserNames),
  }

  request = urllib2.Request(url = url, data = json.dumps(params))
  request.add_header('ContentType', 'application/json; charset=UTF-8')
  response = urllib2.urlopen(request)
  data = response.read()

  # 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 len(ErrMsg) > 0:
    print ErrMsg

  return DeletedList

def main():

  opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(cookielib.CookieJar()))
  urllib2.install_opener(opener)
  
  if getUUID() == False:
    print '获取uuid失败'
    return

  showQRImage()
  time.sleep(1)

  while waitForLogin() != '200':
    pass

  os.remove(QRImagePath)

  if login() == False:
    print '登录失败'
    return

  if webwxinit() == False:
    print '初始化失败'
    return

  MemberList = webwxgetcontact()

  MemberCount = len(MemberList)
  print '通讯录共%s位好友' % MemberCount

  ChatRoomName = ''
  result = []
  for i in xrange(0, int(math.ceil(MemberCount / float(MAX_GROUP_NUM)))):
    UserNames = []
    NickNames = []
    DeletedList = ''
    for j in xrange(0, MAX_GROUP_NUM):
      if i * MAX_GROUP_NUM + j >= MemberCount:
        break

      Member = MemberList[i * MAX_GROUP_NUM + j]
      UserNames.append(Member['UserName'])
      NickNames.append(Member['NickName'].encode('utf-8'))
            
    print '第%s组...' % (i + 1)
    print ', '.join(NickNames)
    print '回车键继续...'
    raw_input()

    # 新建群组/添加成员
    if ChatRoomName == '':
      (ChatRoomName, DeletedList) = createChatroom(UserNames)
    else:
      DeletedList = addMember(ChatRoomName, UserNames)

    DeletedCount = len(DeletedList)
    if DeletedCount > 0:
      result += DeletedList

    print '找到%s个被删好友' % DeletedCount
    # raw_input()

    # 删除成员
    deleteMember(ChatRoomName, UserNames)

  # todo 删除群组


  resultNames = []
  for Member in MemberList:
    if Member['UserName'] in result:
      NickName = Member['NickName']
      if Member['RemarkName'] != '':
        NickName += '(%s)' % Member['RemarkName']
      resultNames.append(NickName.encode('utf-8'))

  print '---------- 被删除的好友列表 ----------'
  print '\n'.join(resultNames)
  print '-----------------------------------'

# windows下编码问题修复
# http://blog.csdn.net/heyuxuanzee/article/details/8442718
class UnicodeStreamFilter: 
  def __init__(self, target): 
    self.target = target 
    self.encoding = 'utf-8' 
    self.errors = 'replace' 
    self.encode_to = self.target.encoding 
  def 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 '本程序的查询结果可能会引起一些心理上的不适,请小心使用...'
  print '回车键继续...'
  raw_input()

  main()

  print '回车键结束'
  raw_input()

感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!

Python 相关文章推荐
python实现ping的方法
Jul 06 Python
Python实现大文件排序的方法
Jul 10 Python
pandas的object对象转时间对象的方法
Apr 11 Python
python实现从pdf文件中提取文本,并自动翻译的方法
Nov 28 Python
python中的句柄操作的方法示例
Jun 20 Python
Python中list循环遍历删除数据的正确方法
Sep 02 Python
python监控nginx端口和进程状态
Sep 06 Python
Python递归调用实现数字累加的代码
Feb 25 Python
python接口自动化之ConfigParser配置文件的使用详解
Aug 03 Python
浅谈python锁与死锁问题
Aug 14 Python
python如何爬取动态网站
Sep 09 Python
关于python类SortedList详解
Sep 04 Python
使用Python将数组的元素导出到变量中(unpacking)
Oct 27 #Python
Python中断言Assertion的一些改进方案
Oct 27 #Python
利用Python实现颜色色值转换的小工具
Oct 27 #Python
Python实现批量检测HTTP服务的状态
Oct 27 #Python
python解决网站的反爬虫策略总结
Oct 26 #Python
Python控制多进程与多线程并发数总结
Oct 26 #Python
Python网络爬虫项目:内容提取器的定义
Oct 25 #Python
You might like
解决控件遮挡问题:关于有窗口元素和无窗口元素
2007/01/28 PHP
php whois查询API制作方法
2011/06/23 PHP
Laravel框架路由配置总结、设置技巧大全
2014/09/03 PHP
ThinkPHP在新浪SAE平台的部署实例
2014/10/31 PHP
php 中奖概率算法实现代码
2017/01/25 PHP
PHP实现微信模拟登陆并给用户发送消息的方法【文字,图片,图文】
2017/06/29 PHP
获取HTML DOM节点元素的方法的总结
2009/08/21 Javascript
js 获取中文拼音,Select自动匹配字母获取值的代码
2009/09/23 Javascript
Jquery封装tab自动切换效果的具体实现
2013/07/13 Javascript
js之ActiveX控件使用说明 new ActiveXObject()
2014/03/03 Javascript
JavaScript function 的 length 属性使用介绍
2014/09/15 Javascript
jquery+html5时钟特效代码分享(可设置闹钟并且语音提醒)
2020/03/30 Javascript
设置jQueryUI DatePicker默认语言为中文
2016/06/04 Javascript
JavaScript实现经典排序算法之冒泡排序
2016/12/28 Javascript
jQuery插件zTree实现获取当前选中节点在同级节点中序号的方法
2017/03/08 Javascript
xmlplus组件设计系列之下拉刷新(PullRefresh)(6)
2017/05/03 Javascript
react.js 父子组件数据绑定实时通讯的示例代码
2017/09/25 Javascript
nodejs 生成和导出 word的实例代码
2018/07/31 NodeJs
vue-router之nuxt动态路由设置的两种方法小结
2018/09/26 Javascript
JS编写兼容IE6,7,8浏览器无缝自动轮播
2018/10/12 Javascript
详解vue的双向绑定原理及实现
2019/05/05 Javascript
Python中生成器和yield语句的用法详解
2015/04/17 Python
Python for Informatics 第11章之正则表达式(二)
2016/04/21 Python
对python判断是否回文数的实例详解
2019/02/08 Python
对Python3 解析html的几种操作方式小结
2019/02/16 Python
python异常处理、自定义异常、断言原理与用法分析
2020/03/23 Python
python批量处理多DNS多域名的nslookup解析实现
2020/06/28 Python
python 获取剪切板内容的两种方法
2020/11/28 Python
捷克钓鱼用品网上商店:Parys.cz
2018/06/15 全球购物
澳大利亚领先的优质葡萄酒拍卖会:Langton’s Fine Wines
2019/03/24 全球购物
介绍下Java中==和equals的区别
2013/09/01 面试题
大学生大二自我鉴定
2013/10/28 职场文书
《宿建德江》教学反思
2014/04/23 职场文书
室内设计专业自荐信
2014/05/31 职场文书
2014班子“三严三实”对照检查材料思想汇报
2014/09/18 职场文书
年度考核表个人总结
2015/03/06 职场文书