利用Python了解微信通信机制,实现查询有多少好友删除你!!

简介: 此篇文章参考微信通信机制,收益匪浅!:http://lib.csdn.net/article/wechat/63831QQ交流群127591054当然也可以写发送消息的代码,机制和上述文章介绍的一样,大家可以参考学习!偶遇:偶尔在论坛发现有外国友人在开源社区发布的Python微信删除好友查看,但是这个作者的代码我这边运行出现了点问题,就是各种问题,我在作者基础上进行研究修改!最终在Python2.7成功运行,之后又用了两天时间把运行环境转移到Python3.5。

此篇文章参考微信通信机制,收益匪浅!:http://lib.csdn.net/article/wechat/63831

QQ交流群127591054

当然也可以写发送消息的代码,机制和上述文章介绍的一样,大家可以参考学习!

偶遇:偶尔在论坛发现有外国友人在开源社区发布的Python微信删除好友查看,但是这个作者的代码我这边运行出现了点问题,就是各种问题,我在作者基础上进行研究修改!最终在Python2.7成功运行,之后又用了两天时间把运行环境转移到Python3.5。几乎完美执行!但是有一个问题我真的无能为力!在当我输出第三组好友名单的时候,就报错了!

报错如下:没办法我就去掉输出好友,就正常了,完整代码在下面,几乎每一句做了详细的注释!

#UnicodeEncodeError: 'UCS-2' codec can't encode characters in position 138-138: Non-BMP character not supported in Tk

原理:简单点就是把好友分组拉入群组,不超过40,别人是看不到的,拉不进俩就代表你被删了!!

但是问题来了,我最近发现腾讯web端操作容易被受限制,我拉了一组或者两组就被限制,说操作频繁了!!所以大家可以拿来学习微信通讯机制!!,不可以用来做坏事哦!虽然可以得到这个用户所有的信息!

完整代码如下:祝大家学习进步!详细注释代码中有写。^~^,就不一句一句讲了。
1、运行代码,会跳出二维码,扫描在手机确认登陆,然后关闭图片,程序自动运行!!
这里写图片描述
2、按操作一步一步执行就可以了~~,具体实现看注释其实不难。

# coding=utf-8  
#Python 3.5
#Author Jack Chiang
import os  
import urllib 
import re  
import http.cookiejar  
import time  
import xml.dom.minidom  
import json  
import sys
import math
import matplotlib.pyplot as plt  
import matplotlib.cbook as cbook
import matplotlib

from matplotlib.font_manager import FontProperties

DEBUG = True #确定当前测试是否查看服务器返回的Json数据  

max_group = 35 # 每组人数  

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

tip = 0 #全局变量:标识是否扫描二维码登陆
uuid = ''  #全局变量:获取登陆值 

base_uri = ''  
redirect_uri = ''  

skey = ''  
wxsid = ''  
wxuin = ''  
pass_ticket = ''  
deviceId = 'e000000000000000'#这个参数是一个15个字节的随机数,所以写死了  

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()),  
    }  
        #使用get方法,通过请求地址:https://login.weixin.qq.com/jslogin?appid=wx782c26e4c19acffb&fun=new&lang=zh_CN&_=时间戳
        #其中,时间戳这个值是当前距离林威治标准时间的毫秒。
    request = urllib.request.Request(url = url, data = urllib.parse.urlencode(params).encode(encoding='UTF-8'))  
    response = urllib.request.urlopen(request)
    #成功则返回:window.QRLogin.code = 200; window.QRLogin.uuid = "UUID"
    data = response.read()

    #1970纪元后经过的浮点秒数time.time()
    #print (time.time())
    #print(data)

        #只要有UUID就可以登陆微信网页版
    # window.QRLogin.code = 200; window.QRLogin.uuid = "oZwt_bFfRg==";  
    regx = r'window.QRLogin.code = (\d+?); window.QRLogin.uuid = "(\S+?)"'  #利用正则表达式匹配  
    pm = re.search(regx,str(data))  

    code = pm.group(1)  #200
    uuid = pm.group(2)  #oZwt_bFfRg==

    if code == '200':  
        return True  

    return False  

#下载微信登陆图片然后打开
def showQRImage():  
    global tip  
    #3、查询是否扫描二维码登录
    #使用get方法,查询地址:https://login.weixin.qq.com/cgi-bin/mmwebwx-bin/login?uuid=XXXXXX&tip=1&_=时间戳
    tip=1
    url = 'https://login.weixin.qq.com/qrcode/%s?tip=%d&_=%d' % (uuid,tip,int(time.time()))  
    """params = {  
                  'tip': '1',  
                   '_': int(time.time()),  
                }"""  
    #这里的XXXXXX是我们刚才获取的uuid,时间戳同上。tip在第一次获取时应为1,这个数是每次查询要变的。
    #拼接地址        
    request  = urllib.request.Request(url = url)  #等价request = urllib.request.Request(url = url, data = urllib.parse.urlencode(params))
    response = urllib.request.urlopen(request)  

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

    #使用matplotlib显示图片
    image_file = cbook.get_sample_data(QRImagePath)  
    image = plt.imread(image_file)

    font = FontProperties(fname=r"D:/Develop//Python27//Lib//site-packages//matplotlib//mpl-data//fonts//ttf//Veral.ttc", size=20)
    s = u'~扫描二维码,然后关闭继续哦~'
    plt.imshow(image)
    plt.title(s,fontproperties=font)
    plt.axis('off') # clear x- and y-axes
    plt.show()
    plt.close()

    #判断当前执行是哪种环境,然后对呀的环境打开图片
    """if sys.platform.find('darwin') >= 0:  #MAC
        os.system('open %s' % QRImagePath)  
    elif sys.platform.find('linux') >= 0:  #Linux
        os.system('xdg-open %s' % QRImagePath)  
    else:                                  #win32
        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()))  
    print(url)
    request = urllib.request.Request(url = url)  
    response = urllib.request.urlopen(request)  #如果不扫描会停在这个位置
    data = response.read()  

    #print(data)


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

    code = pm.group(1)  
    # window.code=408;
    if code == '201': #已扫描  
        print('扫描成功!,请在手机上点击确认以登录')
        tip = 0  
    elif code == '200': #已登录
        #window.code=200;
        #下面链接为个人登陆的网页版,你可以把自己获取的链接复制到百度试一下,看看效果!直接跳到网页版自己的微信。
        #window.redirect_uri="https://wx2.qq.com/cgi-bin/mmwebwx-bin/webwxnewloginpage?ticket=A7YkJKTtu09JTsy7f6zy3w8e@qrticket_0
        #&uuid=********&lang=zh_CN&scan=*********";
        print('正在登录...')  
        regx = r'window.redirect_uri="(\S+?)";'  
        pm = re.search(regx, str(data))
        redirect_uri = pm.group(1) + '&fun=new'  
        base_uri = redirect_uri[:redirect_uri.rfind('/')]
        #print(redirect_uri)
        #print(base_uri)
    elif code == '408': #超时不做操作 
        pass   

    return code  

def login():  
    global skey, wxsid, wxuin, pass_ticket, BaseRequest  
    #访问登录地址在获取地址后面加&fun=new,获得uin、sid、pass_ticket、skey
    request = urllib.request.Request(url = redirect_uri)  
    response = urllib.request.urlopen(request)  
    data = response.read()  

    # print(data)  
    #根据data链接访问得到一下xml数据,进行解析
    ''''' 
        <error> 
            <ret>0</ret> 
            <message></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():  
    #要使用POST方法,访问地址:https://wx2.qq.com/cgi-bin/mmwebwx-bin/webwxinit?r=时间戳&lang=ch_ZN&pass_ticket=XXXXXX
    url = base_uri + '/webwxinit?pass_ticket=%s&skey=%s&r=%s' % (pass_ticket, skey, int(time.time()))
    #print(url)
    #当然这个url需要post方式访问,参数就是之前形成的字典值
    #(BaseRequest)uin、sid、skey分别对应上面步骤4获取的字符串,DeviceID是e后面跟着一个15字节的随机数。
    params = {  
        'BaseRequest': BaseRequest  
    }  

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

    #data = data.encode()

    global ContactList, My  
    dic = json.loads(str(data,encoding='utf-8'))
    #读取服务器通过重重验证过来返回的数据,dic就是当前用户所有信息
    ContactList = dic['ContactList']  
    My = dic['User']  #User就是你的个人信息

        #print(os.getcwd() + '/webwxinit.json');
    if DEBUG == True:

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

    ErrMsg = dic['BaseResponse']['ErrMsg']#捕获服务器异常信息
    if len(ErrMsg) > 0:
        print(ErrMsg)
    Ret = dic['BaseResponse']['Ret']
    if Ret != 0:
        return False

    return True    


    # print(data)   

    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 = urllib.request.Request(url = url)  
    request.add_header('ContentType', 'application/json; charset=UTF-8')  
    response = urllib.request.urlopen(request)  
    data = response.read()  

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

    # print(data)  
    #data是这个用户所有好友数据
    dic = json.loads(str(data,encoding='utf-8'))  
    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 range(len(MemberList) - 1, -1, -1):  #range(x-1,-1,-1)是倒序便利 例如range(10,-1,-1) 10,...0 
        Member = MemberList[i]  
        if Member['VerifyFlag'] & 8 != 0: # 公众号/服务号  24&8=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 = urllib.request.Request(url = url, data = json.dumps(params).encode(encoding='UTF-8'))  
    request.add_header('ContentType', 'application/json; charset=UTF-8')  
    response = urllib.request.urlopen(request)  
    data = response.read()  

    if DEBUG == True:
        #测试数据
        f = open(os.getcwd() + '/webwxChatroo.json', 'wb')  
        f.write(data)  
        f.close()  
    # print(data)  

    dic = json.loads(str(data,encoding='utf-8'))  
    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 = urllib.request.Request(url = url, data = json.dumps(params).encode(encoding='UTF8'))  
    request.add_header('ContentType', 'application/json; charset=UTF-8')  
    response = urllib.request.urlopen(request)  
    data = response.read()  

    # print(data)  

    dic = json.loads(str(data,encoding='utf-8'))

    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 = urllib.request.Request(url = url, data = json.dumps(params).encode(encoding='UTF-8'))  
    request.add_header('ContentType', 'application/json; charset=UTF-8')  
    response = urllib.request.urlopen(request)  
    data = response.read()  

    # print(data)  

    dic = json.loads(str(data,encoding='utf-8'))  
    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 = urllib.request.build_opener(urllib.request.HTTPCookieProcessor(http.cookiejar.CookieJar()))  
    urllib.request.install_opener(opener)  

    if getUUID() == False:  
        print ('获取uuid失败')  
        return  

    showQRImage()  #下载微信登陆图片然后登陆
    time.sleep(1)  

    while waitForLogin() != '200':  
        pass  #循环验证直到为200返回true成功扫描

    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 range(0, int(math.ceil(MemberCount / float(max_group)))):  
        UserNames = []  
        NickNames = []  
        DeletedList = ''  
        for j in range(0, max_group):  
            if i * max_group + j >= MemberCount: #判断 第N组人数是否超过总人数
                break  

            Member = MemberList[i * max_group + j]  
            UserNames.append(Member['UserName'])  #Username是一丢字母,不断变化的
            NickNames.append(Member['NickName'].encode('utf-8'))  #NickName是好友昵称

        print('第%s组...' % (i + 1))

        for k in range(0,NickNames.__len__()):
            NickNames[k] = str(NickNames[k],'utf-8')

        #str1 = ", "
        #str1 = str1.join(NickNames)
        #print(str1)

        #但是下面输出好友会出现问题,在出现第三组的时候就报下面错,不知道如何解决!!,去掉输出完美运行!
        #UnicodeEncodeError: 'UCS-2' codec can't encode characters in position 138-138: Non-BMP character not supported in Tk
        #print(', '.join(NickNames)) #会出现css标签,我想了想那是表情啊~~~哈哈

        print('按回车键继续。。。')
        input()


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

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

        print('找到%s个被删好友' % DeletedCount)  
        #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'))
    for k in range(0,resultNames.__len__()):
        resultNames[k] = str(resultNames[k],'utf-8')

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

if __name__ == '__main__' :  

    print ('开始查询微信删除你的好友信息...')  
    input('回车键继续...')  


    main()  

    input('回车键结束')  



4、测试结果如下:我最近容易受限制!!
这里写图片描述

相关文章
|
23天前
|
Python
自动化微信朋友圈:Python脚本实现自动发布动态
本文介绍如何使用Python脚本自动化发布微信朋友圈动态,节省手动输入的时间。主要依赖`pyautogui`、`time`、`pyperclip`等库,通过模拟鼠标和键盘操作实现自动发布。代码涵盖打开微信、定位朋友圈、准备输入框、模拟打字等功能。虽然该方法能提高效率,但需注意可能违反微信使用条款,存在风险。定期更新脚本以适应微信界面变化也很重要。
140 61
|
26天前
|
存储 小程序 Python
农历节日倒计时:基于Python的公历与农历日期转换及节日查询小程序
### 农历节日倒计时:基于Python的公历与农历日期转换及节日查询小程序 该程序通过`lunardate`库实现公历与农历的日期转换,支持闰月和跨年处理,用户输入农历节日名称后,可准确计算距离该节日还有多少天。功能包括农历节日查询、倒计时计算等。欢迎使用! (239字符)
184 86
|
1天前
|
缓存 JSON 数据处理
Python进阶:深入理解import机制与importlib的妙用
本文深入解析了Python的`import`机制及其背后的原理,涵盖基本用法、模块缓存、导入搜索路径和导入钩子等内容。通过理解这些机制,开发者可以优化模块加载速度并确保代码的一致性。文章还介绍了`importlib`的强大功能,如动态模块导入、实现插件系统及重新加载模块,展示了如何利用这些特性编写更加灵活和高效的代码。掌握这些知识有助于提升编程技能,充分利用Python的强大功能。
12 4
|
1月前
|
Android开发 开发者 Python
通过标签清理微信好友:Python自动化脚本解析
微信已成为日常生活中的重要社交工具,但随着使用时间增长,好友列表可能变得臃肿。本文介绍了一个基于 Python 的自动化脚本,利用 `uiautomator2` 库,通过模拟用户操作实现根据标签批量清理微信好友的功能。脚本包括环境准备、类定义、方法实现等部分,详细解析了如何通过标签筛选并删除好友,适合需要批量管理微信好友的用户。
69 7
|
2月前
|
UED 开发者 Python
Python中的异常处理机制
Python中的异常处理机制
49 2
|
2月前
|
监控 Java 开发者
Python的垃圾收集机制有哪些?
Python的垃圾收集机制有哪些?
|
3月前
|
数据采集 人工智能 自然语言处理
AI Agent 金融助理0-1 Tutorial 利用Python实时查询股票API的FinanceAgent框架构建股票(美股/A股/港股) AI Finance Agent
金融领域Finance AI Agents方面的工作,发现很多行业需求和用户输入的 query都是和查询股价/行情/指数/财报汇总/金融理财建议相关。如果需要准确的 金融实时数据就不能只依赖LLM 来生成了。常规的方案包括 RAG (包括调用API )再把对应数据和prompt 一起拼接送给大模型来做文本生成。稳定的一些商业机构的金融数据API基本都是收费的,如果是以科研和demo性质有一些开放爬虫API可以使用。这里主要介绍一下 FinanceAgent,github地址 https://github.com/AI-Hub-Admin/FinanceAgent
|
2月前
|
测试技术 API 数据安全/隐私保护
Python连接到Jira实例、登录、查询、修改和创建bug
通过使用Python和Jira的REST API,可以方便地连接到Jira实例并进行各种操作,包括查询、修改和创建Bug。`jira`库提供了简洁的接口,使得这些操作变得简单易行。无论是自动化测试还是开发工作流的集成,这些方法都可以极大地提高效率和准确性。希望通过本文的介绍,您能够更好地理解和应用这些技术。
301 0
|
3月前
|
iOS开发 MacOS Python
Python编程小案例—利用flask查询本机IP归属并输出网页图片
Python编程小案例—利用flask查询本机IP归属并输出网页图片
38 1
|
3月前
|
人工智能 文字识别 API
Python反爬机制-验证码(二)
Python反爬机制-验证码(二)
28 1

热门文章

最新文章