python轻松查到删除自己的微信好友


Posted in Python onJanuary 10, 2016

前言

python轻松查到删除自己的微信好友

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

原理

新建群组,如果加不进来就是被删好友了(不要在群组里讲话,别人是看不见的)。
用的是微信网页版的接口,还有些小问题,不过现在结果好像有疏漏一小部分,原因不明……也没试过被拉黑的情况。最终会遗留下一个只有自己的群组,需要手工删一下。

方法

下载 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下编码问题修复
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()

友尽

亲测有效,有 11 个删除我的「好友」,默默归类为 11 个相亲男,还有比我伤的更深的么?

Python 相关文章推荐
Python的Django框架中的select_related函数对QuerySet 查询的优化
Apr 01 Python
在Python中使用mongoengine操作MongoDB教程
Apr 24 Python
Python 类与元类的深度挖掘 II【经验】
May 06 Python
Python实现TCP协议下的端口映射功能的脚本程序示例
Jun 14 Python
浅谈python jieba分词模块的基本用法
Nov 09 Python
python中实现数组和列表读取一列的方法
Apr 03 Python
从DataFrame中提取出Series或DataFrame对象的方法
Nov 10 Python
Pandas GroupBy对象 索引与迭代方法
Nov 16 Python
Python中包的用法及安装
Feb 11 Python
python2 对excel表格操作完整示例
Feb 23 Python
Python调用接口合并Excel表代码实例
Mar 31 Python
Python中Pyspider爬虫框架的基本使用详解
Jan 27 Python
如何处理Python3.4 使用pymssql 乱码问题
Jan 08 #Python
Python argv用法详解
Jan 08 #Python
详解Python爬虫的基本写法
Jan 08 #Python
黑科技 Python脚本帮你找出微信上删除你好友的人
Jan 07 #Python
星球大战与Python之间的那些事
Jan 07 #Python
python高手之路python处理excel文件(方法汇总)
Jan 07 #Python
Python解析最简单的验证码
Jan 07 #Python
You might like
java EJB 加密与解密原理的一个例子
2008/01/11 PHP
PHP获取短链接跳转后的真实地址和响应头信息的方法
2014/07/25 PHP
详解PHP的Laravel框架中Eloquent对象关系映射使用
2016/02/26 PHP
php+ajax登录跳转登录实现思路
2016/07/31 PHP
微信网页授权(OAuth2.0) PHP 源码简单实现
2016/08/29 PHP
PHP共享内存使用与信号控制实例分析
2018/05/09 PHP
lnmp安装多版本PHP共存的方法详解
2018/08/02 PHP
laravel实现图片上传预览,及编辑时可更换图片,并实时变化的例子
2019/11/14 PHP
JS获取父节点方法
2009/08/20 Javascript
几个比较经典常用的jQuery小技巧
2010/03/01 Javascript
JavaScript解析json格式数据简单示例
2014/12/09 Javascript
AngularJS入门教程之Scope(作用域)
2016/07/27 Javascript
Bootstrap树形菜单插件TreeView.js使用方法详解
2016/11/01 Javascript
jQuery实现级联下拉框实战(5)
2017/02/08 Javascript
浅谈JavaScript正则表达式-非捕获性分组
2017/03/08 Javascript
微信小程序实现顶部普通选项卡效果(非swiper)
2020/06/19 Javascript
js Date()日期函数浏览器兼容问题解决方法
2017/09/12 Javascript
vue input 输入校验字母数字组合且长度小于30的实现代码
2018/05/16 Javascript
redux.js详解及基本使用
2019/05/24 Javascript
JS变量提升及函数提升实例解析
2020/09/03 Javascript
Python中使用md5sum检查目录中相同文件代码分享
2015/02/02 Python
Python函数式编程指南(一):函数式编程概述
2015/06/24 Python
使用selenium和pyquery爬取京东商品列表过程解析
2019/08/15 Python
python中读入二维csv格式的表格方法详解(以元组/列表形式表示)
2020/04/24 Python
python 解决mysql where in 对列表(list,,array)问题
2020/06/06 Python
python中用ggplot绘制画图实例讲解
2021/01/26 Python
css3实现一个div设置多张背景图片及background-image属性实例演示
2017/08/10 HTML / CSS
工作表现评语
2014/01/19 职场文书
2014年基层党支部工作总结
2014/12/04 职场文书
云冈石窟导游词
2015/02/04 职场文书
会计求职信怎么写
2015/03/20 职场文书
五星级酒店宣传口号
2015/12/25 职场文书
JS数组的常用方法整理
2021/03/31 Javascript
vue 实现上传组件
2021/05/31 Vue.js
详解Python requests模块
2021/06/21 Python
Python极值整数的边界探讨分析
2021/09/15 Python