失眠网,内容丰富有趣,生活中的好帮手!
失眠网 > 用Python requests模拟登录微信网页版 并接收发送消息

用Python requests模拟登录微信网页版 并接收发送消息

时间:2024-06-04 05:12:33

相关推荐

用Python requests模拟登录微信网页版 并接收发送消息

首先,网页版微信登录大致分为以下几个流程(都是大家可以通过抓包得到):

1、登陆主页后,会生成一个UUID,这是个用户标识,在后面请求二维码会用到

'''遇到问题没人解答?小编创建了一个Python学习交流QQ群:85766 寻找有志同道合的小伙伴,互帮互助,群里还有不错的视频学习教程和PDF电子书!'''def get_uuid(self):'''获取uuid'''url = 'https://login./jslogin?appid=wx782c26e4c19acffb&redirect_uri=https%3A%2F%%2Fcgi-bin%2Fmmwebwx-bin%2Fwebwxnewloginpage&fun=new&lang=zh_CN&_={}'.format(get_time())response = self.session.get(url).textself.uuid = re.findall(r'uuid = "(.*?)"',response)[0] # 文本较少,用正则匹配即可return self.uuid

2、请求二维码图片

'''遇到问题没人解答?小编创建了一个Python学习交流QQ群:85766 寻找有志同道合的小伙伴,互帮互助,群里还有不错的视频学习教程和PDF电子书!'''def qrcode(self):url = 'https://login./qrcode/{}'.format(self.uuid)response = self.session.get(url).content # 请求得到二维码,由于是图片,得到字节码即可with open ('qrcode.jpg','wb') as f:f.write(response) # 把二维码保存到一张图片里im = Image.open('qrcode.jpg')im.show() # 把二维码图片展示出来

3、扫描二维码,得到重定向的链接

'''遇到问题没人解答?小编创建了一个Python学习交流QQ群:85766 寻找有志同道合的小伙伴,互帮互助,群里还有不错的视频学习教程和PDF电子书!'''def get_redirect_uri(self):while True: # 由于需要不断请求,让我们有时间来扫描二维码url = 'https://login./cgi-bin/mmwebwx-bin/login?loginicon=true&uuid={}&tip=0&r=-2109595288&_={}'.format(self.uuid,get_time())result = self.session.get(url,allow_redirects=False)code = re.findall(r'window.code=(.*?);',result.text)[0]if code == '200': # 没有扫描的时候是400,扫描之后就是200print('已成功扫描二维码!')breakself.redirect_uri = re.findall(r'window.redirect_uri="(.*?)"',result.text)[0] # 得到一个链接,请求之后会得到一些有用的参数

这个url里面有个参数在前面请求应答中没有的,在js中可以找到,大概是个13位的时间戳

4、请求上面得到的链接,得到一些必要的参数(这些参数在后面的登录、收发消息都是必需的),注意这里一定要不允许重定向,因为请求这个url的时候,会跳转到一个初始化的链接,这样我们将不能正确获得这些参数。

'''遇到问题没人解答?小编创建了一个Python学习交流QQ群:85766 寻找有志同道合的小伙伴,互帮互助,群里还有不错的视频学习教程和PDF电子书!'''def get_require_data(self):result = self.session.get(self.redirect_uri,allow_redirects=False).text # 这里注意一定要去掉重定向self.skey = re.findall(r'<skey>(.*?)</skey>',result)[0] # 这里用Beautifulsoup也能解析,文本是xml格式的,用匹配标签就可以得到self.wxsid = re.findall(r'<wxsid>(.*?)</wxsid>',result)[0]self.wxuin = re.findall(r'<wxuin>(.*?)</wxuin>',result)[0]self.pass_ticket = re.findall(r'<pass_ticket>(.*?)</pass_ticket>',result)[0]

5、发送登录请求

'''遇到问题没人解答?小编创建了一个Python学习交流QQ群:85766 寻找有志同道合的小伙伴,互帮互助,群里还有不错的视频学习教程和PDF电子书!'''def login(self):url = '/cgi-bin/mmwebwx-bin/webwxinit?r=-2109580211&pass_ticket={}'.format(self.pass_ticket)params = {"BaseRequest":{"Uin":self.wxuin,"Sid":self.wxsid,"Skey":self.skey,"DeviceID":get_DeviceID(), # DeviceID这个参数在前面的应答中没有找到,它是js生成的,通过读js代码,我们可以构造出来}}result = self.session.post(url,data=json.dumps(params,ensure_ascii=False))result.encoding = 'utf-8'data = result.json()user = data['User']nickname = user['NickName']username = user['UserName']self.user_list[nickname] = username # 把自己账号的昵称和用户编号保存起来,方便后面收发消息self.synckey_list = data['SyncKey'] # synckey 用于后面同步消息print('已成功登录!!')self.synckey = format_synckey(self.synckey_list['List']) # 把 synckey构造成查询字符串的模式

至此,就完成了基本的登陆认证过程,其实大部分的登录都差不多,可能有得是通过验证码和账号密码加密的方式,这些到后面再说

6、得到好友列表并保存起来

def get_userlist(self):'''把用户的好友列表保存起来,方便后面收发消息'''url = '/cgi-bin/mmwebwx-bin/webwxgetcontact?pass_ticket={}&r={}&seq=0&skey={}'.format(self.pass_ticket,get_time(),self.skey)response = self.session.get(url)response.encoding = 'utf-8'result = response.json()memberlist = result['MemberList']for member in memberlist:nickname = member['NickName']username = member['UserName']self.user_list[nickname] = username # 按照昵称-用户编号的一一对应关系保存

下面就到了比较繁琐的环节了,收发消息:

我们在登录的时候就得到一个synckey了,这个东西在每次收消息的请求中都要带上,而且每次收发消息,这个值都会向服务器请求更新一次。那么我们怎么确定正在收发消息呢,微信网页版用的是轮询的方式发送一个请求,这个请求的响应大概是{retcode:”0″,selector:”0″}这样的,如果selector变得不为0了,说明有消息要收发。所以我们也可以通过不断地发送请求,然后判断响应里的selector的值来处理。

1、更新synckey

def get_new_synckey(self): # 得到最新的synckey 发送或者接收消息后都有这个操作url = '/cgi-bin/mmwebwx-bin/webwxsync?sid={}&skey={}&pass_ticket={}'.format(self.wxsid,self.skey,self.pass_ticket)data = {"BaseRequest":{"Uin":self.wxuin,"Sid":self.wxsid,"Skey":self.skey,"DeviceID":get_DeviceID()},"SyncKey":self.synckey_list,"rr":2112925520}response = self.session.post(url,data=json.dumps(data,ensure_ascii=False))response.encoding = 'utf8'result = response.json()self.synckey_list = result['SyncKey']self.synckey = format_synckey(self.synckey_list['List'])

2、检查selector值是否不为0

def sync_check(self): # 检查是否有新消息while True:# 注意这里的synckey是在url里面,所以要进行urlencode,而且synckey改变之后,url也会变,所以url要放在while True里面url = 'https://webpush./cgi-bin/mmwebwx-bin/synccheck?r={}&skey={}&sid={}&uin={}&deviceid={}&{}'.format(get_time(),self.skey,self.wxsid,self.wxuin,get_DeviceID(),self.synckey) response = self.session.get(url)response.encoding = 'utf8'result = response.text# print('正在轮询是否有新消息...')selector = re.findall(r'selector:"(.*?)"',result)[0]if selector != '0':self.get_msg() # 我这里发消息是在另一个线程,收消息在这个线程self.get_new_synckey() # 每次都需要更新

3、接受消息

'''遇到问题没人解答?小编创建了一个Python学习交流QQ群:85766 寻找有志同道合的小伙伴,互帮互助,群里还有不错的视频学习教程和PDF电子书!'''def get_msg(self):'''接收消息'''url = ' /cgi-bin/mmwebwx-bin/webwxsync?sid={}&skey={}&pass_ticket={}'.format(self.wxsid,self.skey,self.pass_ticket)data = {"BaseRequest":{"Uin":self.wxuin,"Sid":self.wxsid,"Skey":self.skey,"DeviceID":get_DeviceID()},"SyncKey":self.synckey_list,"rr":-2123282759}response = self.session.post(url,data=json.dumps(data))response.encoding = 'utf-8'result = response.json()self.synckey_list = result['SyncKey'] # 接受消息的时候,响应里面有这个值,在更新synckey的时候,参数和响应里都有synckeyself.synckey = format_synckey(self.synckey_list['List'])msglist = result['AddMsgList']for msg in msglist:if msg['ToUserName'] == self.user_list['XXXX']: # 这里面填你自己微信的昵称,不过加上之后不会受到群消息,大家可以试试不加这个判断fromName = msg['FromUserName']for k,v in self.user_list.items():if v == fromName:fromNickName = kcontent = msg['Content']print('来自{}的消息:{}'.format(fromNickName,content))

4、发送消息

'''遇到问题没人解答?小编创建了一个Python学习交流QQ群:85766 寻找有志同道合的小伙伴,互帮互助,群里还有不错的视频学习教程和PDF电子书!'''def send_msg(self):url = '/cgi-bin/mmwebwx-bin/webwxsendmsg?pass_ticket={}'.format(self.pass_ticket)while True:msg = input('>>>>>')if msg == 'q':breakdata = {"BaseRequest":{"Uin":self.wxuin,"Sid":self.wxsid,"Skey":self.skey,"DeviceID":get_DeviceID()},"Msg":{"Type":1,"Content":msg,"FromUserName":self.user_list['xxx'], # 这里填你自己的昵称"ToUserName":self.user_list['xxx'], # 这里填你想发送消息的好友的昵称,你也可以用input键盘输入的方式"LocalID":get_time(),"ClientMsgId":get_time()},"Scene":0}self.session.post(url,data=(json.dumps(data,ensure_ascii=False)).encode('utf-8'))self.get_new_synckey() # 发送消息之后也要更新synckey

5、把发送消息和接受消息写成多线程的方式

大致流程就是这样啦!下面展示全部代码:

1 import time2 import re3 import random4 import requests5 import urllib36 import json7 from urllib import parse8 from PIL import Image9 from threading import Thread10 11 urllib3.disable_warnings()12 13 14 def get_time():15return str(int(time.time()*1000))16 17 def get_DeviceID():18return 'e'+str(round(random.random(),15))[2:17]19 20 def format_synckey(synckey_list):21'''22把列表形式转成查询字符串23'''24tem_synckey = ''25for synckey in synckey_list:26 tem_synckey += str(synckey['Key']) + '_' +str(synckey['Val']) + '|'27new_synckey = {'synckey':tem_synckey.rstrip('|')}28return parse.urlencode(new_synckey)29 30 class WeChat():31def __init__(self):32 headers = {33 'User-Agent': 'Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.186 Safari/537.36'34 } # 请求头信息35 proxies = {36 'http': '192.168.105.71:80',37 'https': '192.168.105.71:80'38 } # 使用代理39 self.user_list = {}40 self.session = requests.session()41 self.session.headers = headers42 self.session.proxies = proxies43 self.session.verify = False44 45def get_uuid(self):46 '''获取uuid'''47 url = 'https://login./jslogin?appid=wx782c26e4c19acffb&redirect_uri=https%3A%2F%%2Fcgi-bin%2Fmmwebwx-bin%2Fwebwxnewloginpage&fun=new&lang=zh_CN&_={}'.format(get_time())48 response = self.session.get(url).text49 self.uuid = re.findall(r'uuid = "(.*?)"',response)[0] # 文本较少,用正则匹配即可50 return self.uuid51 52def qrcode(self):53 url = 'https://login./qrcode/{}'.format(self.uuid)54 response = self.session.get(url).content # 请求得到二维码,由于是图片,得到字节码即可55 with open ('qrcode.jpg','wb') as f:56 f.write(response) # 把二维码保存到一张图片里57 im = Image.open('qrcode.jpg')58 im.show() # 把二维码图片展示出来59 60def get_redirect_uri(self):61 while True: # 由于需要不断请求,让我们有时间来扫描二维码62 url = 'https://login./cgi-bin/mmwebwx-bin/login?loginicon=true&uuid={}&tip=0&r=-2109595288&_={}'.format(self.uuid,get_time())63 result = self.session.get(url,allow_redirects=False)64 code = re.findall(r'window.code=(.*?);',result.text)[0]65 if code == '200': # 没有扫描的时候是400,扫描之后就是6 print('已成功扫描二维码!')67 break68 self.redirect_uri = re.findall(r'window.redirect_uri="(.*?)"',result.text)[0] # 得到一个链接,请求之后会得到一些有用的参数69 70def get_require_data(self):71 result = self.session.get(self.redirect_uri,allow_redirects=False).text # 这里注意一定要去掉重定向72 self.skey = re.findall(r'<skey>(.*?)</skey>',result)[0] # 这里用Beautifulsoup也能解析,文本是xml格式的,用匹配标签就可以得到73 self.wxsid = re.findall(r'<wxsid>(.*?)</wxsid>',result)[0]74 self.wxuin = re.findall(r'<wxuin>(.*?)</wxuin>',result)[0]75 self.pass_ticket = re.findall(r'<pass_ticket>(.*?)</pass_ticket>',result)[0]76 77def login(self):78 url = '/cgi-bin/mmwebwx-bin/webwxinit?r=-2109580211&pass_ticket={}'.format(self.pass_ticket)79 params = {80 "BaseRequest":{81 "Uin":self.wxuin,82 "Sid":self.wxsid,83 "Skey":self.skey,84 "DeviceID":get_DeviceID(), # DeviceID这个参数在前面的应答中没有找到,它是js生成的85 }86 }87 result = self.session.post(url,data=json.dumps(params,ensure_ascii=False))88 result.encoding = 'utf-8'89 data = result.json()90 user = data['User']91 nickname = user['NickName']92 username = user['UserName']93 self.user_list[nickname] = username # 把自己账号的昵称和用户编号保存起来,方便后面收发消息94 self.synckey_list = data['SyncKey'] # synckey 用于后面同步消息95 print('已成功登录!!')96 self.synckey = format_synckey(self.synckey_list['List']) # 把 synckey构造成查询字符串的模式97 98 99 100def get_userlist(self):101 '''把用户的好友列表保存起来,方便后面收发消息'''102 url = '/cgi-bin/mmwebwx-bin/webwxgetcontact?pass_ticket={}&r={}&seq=0&skey={}'.format(self.pass_ticket,get_time(),self.skey)103 response = self.session.get(url)104 response.encoding = 'utf-8'105 result = response.json()106 memberlist = result['MemberList']107 for member in memberlist:108 nickname = member['NickName']109 username = member['UserName']110 self.user_list[nickname] = username # 按照昵称-用户编号的一一对应关系保存111 112def get_new_synckey(self): # 得到最新的synckey 发送或者接收消息后都有这个操作113 url = '/cgi-bin/mmwebwx-bin/webwxsync?sid={}&skey={}&pass_ticket={}'.format(self.wxsid,self.skey,self.pass_ticket)114 data = {"BaseRequest":{"Uin":self.wxuin,"Sid":self.wxsid,"Skey":self.skey,"DeviceID":get_DeviceID()},"SyncKey":self.synckey_list,"rr":2112925520}115 response = self.session.post(url,data=json.dumps(data,ensure_ascii=False))116 response.encoding = 'utf8'117 result = response.json()118 self.synckey_list = result['SyncKey']119 self.synckey = format_synckey(self.synckey_list['List'])120 121def sync_check(self): # 检查是否有新消息122 while True:123 # 注意这里的synckey是在url里面,所以要进行urlencode,而且synckey改变之后,url也会变,所以url要放在while True里面124 url = 'https://webpush./cgi-bin/mmwebwx-bin/synccheck?r={}&skey={}&sid={}&uin={}&deviceid={}&{}'.format(get_time(),self.skey,self.wxsid,self.wxuin,get_DeviceID(),self.synckey)125 response = self.session.get(url)126 response.encoding = 'utf8'127 result = response.text128 # print('正在轮询是否有新消息...')129 selector = re.findall(r'selector:"(.*?)"',result)[0]130 if selector != '0':131 self.get_msg() # 我这里发消息是在另一个线程,收消息在这个线程132 self.get_new_synckey() # 每次都需要更新133 134 135 136def send_msg(self):137 url = '/cgi-bin/mmwebwx-bin/webwxsendmsg?pass_ticket={}'.format(self.pass_ticket)138 while True:139 msg = input('>>>>>')140 if msg == 'q':141 break142 data = {143 "BaseRequest":{144 "Uin":self.wxuin,145 "Sid":self.wxsid,146 "Skey":self.skey,147 "DeviceID":get_DeviceID()},148 "Msg":{149 "Type":1,150 "Content":msg,151 "FromUserName":self.user_list['xxx'], # 这里填你自己微信昵称152 "ToUserName":self.user_list['xxx'], # 这里填你想发送消息的好友的昵称,你也可以用input键盘输入的方式153 "LocalID":get_time(),154 "ClientMsgId":get_time()},155 "Scene":0156 }157 158 self.session.post(url,data=(json.dumps(data,ensure_ascii=False)).encode('utf-8'))159 self.get_new_synckey() # 发送消息之后也会更新synckey160 161 162 163def get_msg(self):164 '''接收消息'''165 url = ' /cgi-bin/mmwebwx-bin/webwxsync?sid={}&skey={}&pass_ticket={}'.format(self.wxsid,self.skey,self.pass_ticket)166 data = {167 "BaseRequest":{168 "Uin":self.wxuin,169 "Sid":self.wxsid,170 "Skey":self.skey,171 "DeviceID":get_DeviceID()},172 "SyncKey":self.synckey_list,173"rr":-2123282759}174 response = self.session.post(url,data=json.dumps(data))175 response.encoding = 'utf-8'176 result = response.json()177 self.synckey_list = result['SyncKey'] # 接受消息的时候,响应里面有这个值,在更新synckey的时候,参数和响应里都有synckey178 self.synckey = format_synckey(self.synckey_list['List'])179 msglist = result['AddMsgList']180 for msg in msglist:181 if msg['ToUserName'] == self.user_list['XXXX']: # 这里面填你自己微信的昵称,不过加上之后不会受到群消息,大家可以试试不加这个判断182 fromName = msg['FromUserName']183 for k,v in self.user_list.items():184 if v == fromName:185fromNickName = k186content = msg['Content']187print('来自{}的消息:{}'.format(fromNickName,content))188 189def main(self):190 self.get_uuid()191 self.qrcode()192 self.get_redirect_uri()193 self.get_require_data()194 self.login()195 self.get_userlist()196 send_msg = Thread(target=self.send_msg)197 recieve_msg = Thread(target=self.sync_check)198 send_msg.start()199 recieve_msg.start()200 send_msg.join()201 recieve_msg.join()202 203 204 if __name__ == '__main__':205wechat = WeChat()206wechat.main()

在这理,我只实现了文本消息,至于表情以及图片,还没有实现,大家可以完善一下。

如果觉得《用Python requests模拟登录微信网页版 并接收发送消息》对你有帮助,请点赞、收藏,并留下你的观点哦!

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。