前言:

  今天我们利用requests模块+django+bs4浏览器来实现一个web微信的基本功能,主要实现的功能如下

  a、实现返回二维码

  b、实现手机扫码后二维码变成变成头像

  c、实现手机点击登陆成功显示微信的最近联系人

  d、实现显示所有的联系人

  e、实现发送消息

  

  下面我们就开始实现上述的功能,在看这篇博客的之前,读者朋友需要去了解一下长轮询的知识,因为wei微信的登陆就用到了长轮询,首先我们先把web登陆的流程梳理一下,然后在实现我们的功能

一、web微信登陆分析

1、web微信二维码分析

a、首先拿到url,这个请求是get请求

https://login.wx2.qq.com/jslogin?appid=wx782c26e4c19acffb&redirect_uri=https://wx2.qq.com/cgi-bin/mmwebwx-bin/webwxnewloginpage&fun=new&lang=zh_&_=1555510256420

  

这个url很好构建,只有1555510256420这个参数需要我们认为生成,其他他就是时间戳*1000,然后取整,生成的方法如下

t = int(time.time() * 1000)

  

b、分析这个url的返回值

c、查看网页的源代码,看下这个二维码到底是什么

看下img标签的src属性,有没有注意到,src的这一段字符串oaKKJgJRhA==,是我们返回二维码的url返回的字符串,所以我们就可以拼接出来二维码这个图片的src的地址

https://login.weixin.qq.com/qrcode/oaKKJgJRhA==  

  

2、等待用户扫码

这里就用到了一个长轮询,如果客户一直没有扫码,则会hang住,等待客户的扫码

a、先来分析一下url

https://login.wx2.qq.com/cgi-bin/mmwebwx-bin/login?loginicon=true&uuid=oeoQNe1EiA==&tip=1&r=-732967182&_=1555511127069

 

这个url有2个地方需要我们来构建

第一个参数就上一步返回的字符串,第二个参数就是一个还是一个时间戳

b、在来看下这个url返回了什么

只有一个状态码408

结论:如果url的返回的code为408,则表示等待用户扫码

3、web微信显示头像分析

手机扫码后,二维码变成头像

a、先来分析url

https://login.wx2.qq.com/cgi-bin/mmwebwx-bin/login?loginicon=true&uuid=Qfn4ldhuNQ==&tip=1&r=-732688468&_=1555510848123

  

这个url和上面的url一样,所以我们知道,第一步返回的字符串非常重要,所以我们要把这段字符串放在session中

b、在来看下url的返回值

这里返回了一段字符串,code为201,后面那一段字符串是头像的地址

c、我们在来看下html中的img标签的src的地址

结论:返回201,则证明用户已经扫码成功

4、web微信登陆分析

a、首先url还是之前的url,这里就不做分析

https://login.wx2.qq.com/cgi-bin/mmwebwx-bin/login?loginicon=true&uuid=YacjFJrAfA==&tip=0&r=-733737113&_=1555511755717

  

b、看下这次请求的返回值

这里有一个跳转的url,也就是当我们点击登陆后,会跳转到这个url

这里还有一个返回码是200

结论:状态码返回200,则证明登陆成功

5、分析web微信的跳转url

a、分析一下这次请求的返回值

<error><ret>0</ret><message></message><skey>@crypt_90b16895_59f7cbfc1c217310b90558af662ea9c7</skey><wxsid>VP1xxDiAiU5Xz8gN</wxsid><wxuin>1632086000</wxuin><pass_ticket>w%2BIW73Y3XXFLqfA%2BBworrfgKu5aRlyXW%2F57wtMPYwrP%2BWnDW3ieWQ8jBmUUTbawy</pass_ticket><isgrayscale>1</isgrayscale></error>

  

这个返回值非常重要,我们后面登陆后需要做的操作都需要这里的信息。所以这个信息我们也要组合一下放在session后,方便的后面的请求使用

6、web微信显示最近联系人流程分析

访问为跳转url后,拿到返回值信息,web微信又会发送一个post请求,获取最近联系人信息

a、先看下url,这里url就需要用到上面跳转url的返回值的信息来拼接

https://wx2.qq.com/cgi-bin/mmwebwx-bin/webwxinit?r=-733594626&pass_ticket=w%2BIW73Y3XXFLqfA%2BBworrfgKu5aRlyXW%2F57wtMPYwrP%2BWnDW3ieWQ8jBmUUTbawy

  

b、这个请求的返回值就是最近联系人

c、我们就可以把这些数据渲染到html页面就可以了

7、web微信显示全部联系人

点击这里,就会显示全部联系人

a、分析一下url

https://wx2.qq.com/cgi-bin/mmwebwx-bin/webwxgetcontact?pass_ticket=w%2BIW73Y3XXFLqfA%2BBworrfgKu5aRlyXW%2F57wtMPYwrP%2BWnDW3ieWQ8jBmUUTbawy&r=1555511910553&seq=0&skey=@crypt_90b16895_59f7cbfc1c217310b90558af662ea9c7

  

我们完全可以根据session中的数据拼接这个字符串

b、这次请求的返回信息就是所有的联系人

8、web发送消息

发送消息是一个post的请求

a、先来分析url

https://wx2.qq.com/cgi-bin/mmwebwx-bin/webwxsendmsg?pass_ticket=w%2BIW73Y3XXFLqfA%2BBworrfgKu5aRlyXW%2F57wtMPYwrP%2BWnDW3ieWQ8jBmUUTbawy

  

我们可以通过session中的数据拼接出这个url

b、在来看下这次post携带的请求体,我们完全可以通过session中的数据拼接出这个请求体

c、分析msg这个信息

第一条是时间戳

第二条是发送的内容

第三条发送者的微信id

第四条也是时间戳

第五条是接受者的微信id

二、我们的代码实现

通过上面的分析,我相信大家对web微信的请求已经非常了解了,下面我们使用requests+bs4+djangon来实现一个建议的web微信

1、首先看下登陆的html,重点看下我的注释

2、进入views文件,看下返回二维码的视图函数,我们注意到,前面的html需要q_code这个变量来渲染img标签的src的路径,显示二维码

3、然后后看下等待用户扫码的后台逻辑

4、看下前端处理408返回码的逻辑

5、在来看下用户扫码后的后台逻辑

6、在看下前端收到201的返回值处理逻辑,首先修改二维码的地址为头像的地址,然后再次发送一次请求,等待用户点击确认

7、在看下后端处理用户点击登陆的逻辑

8、在看下前端处理200请求的逻辑,会跳转到一个最近联系人的页面

9、我们在看下这个url对应的视图函数,这个视图函数是返回最近联系人的函数,需要携带规定的请求体,这些请求体已经被存储到session中

10、在看下index.html这个页面,这个数据结构比较简单,大家自己自己抓包看

11、我们再看下查所有人联系人

12、看下对应的视图函数,拼接url,然后把返回值返回给前端

13、前端渲染数据即可

14、在看发送信息的前端页面

15、再看下后端的处理逻辑,主要是拼接url和处理中文的信息

def sendmsg(request):
if request.method == "GET":
return render(request,"sendmsg.html") else:
from_user = request.POST.get("from_user")
to_user = request.POST.get("to_user")
content = request.POST.get("content") data_dict = {
"BaseRequest":{
"DeviceID":"e461335461567419",
"Sid":request.session["temp_dict"].get("wxsid"),
"Skey":request.session["temp_dict"].get("skey"),
"Uin":request.session["temp_dict"].get("wxuin")
},
"Msg":{
"ClientMsgId":int(time.time() * 1000),
"Content":content,
"FromUserName":from_user,
"LocalID":int(time.time() * 1000),
"ToUserName":to_user,
"Type":1
},
"Scene":0
}
rep = requests.post(
url= "https://wx2.qq.com/cgi-bin/mmwebwx-bin/webwxsendmsg?lang=zh_CN&pass_ticket={p}".format(p = request.session["temp_dict"]["pass_ticket"]), # 1、方式1,处理不了中文,由于json的问题
# json=data_dict # 2、方式2,解决了json处理不了中文的问题,但是微信用的解码是不是常见的解码方式,所以还是处理不了中文
# data = json.dumps(
# data_dict,
# ensure_ascii=False
# ) # 3、方式3,直接发送二进制文件,就可以解决发送中文的问题
data = bytes(json.dumps(
data_dict,
ensure_ascii=False
),encoding="utf-8")
)
print(rep.text) return HttpResponse("success")

  

三、整体的后端代码

from django.shortcuts import render
from django.shortcuts import HttpResponse
from django.shortcuts import redirect
import requests
import re
# Create your views here. import time
def login(request):
if request.method.lower() == "get":
t = int(time.time() * 1000)
url = "https://login.wx.qq.com/jslogin?appid=wx782c26e4c19acffb&redirect_uri=https%3A%2F%2Fwx.qq.com%2Fcgi-bin%2Fmmwebwx-bin%2Fwebwxnewloginpage&fun=new&lang=zh_CN&_={t}"
res = requests.get(url=url)
# window.QRLogin.code = 200;
# window.QRLogin.uuid = "oc86pbX-hQ==";
re_obj = re.compile('= "(.*==)";$')
q_code = re_obj.findall(res.text)[0]
request.session["q_code"] = q_code
return render(request,"login.html",locals()) import json
import re
from bs4 import BeautifulSoup
# BeautifulSoup还可以处理xml文档
def checklogin(request):
if request.method.lower() == "get":
res_dict = {"code":408,"img":None,"url":None}
code = request.session["q_code"]
t = int(time.time() * 1000)
url = "https://login.wx.qq.com/cgi-bin/mmwebwx-bin/login?loginicon=true&uuid={code}&tip=0&r=-131537270&_={t}".format(code = code,t = t)
rep = requests.get(url=url)
if "window.code=408;" in rep.text:
return HttpResponse(json.dumps(res_dict)) elif "window.code=201;" in rep.text:
# 扫码成功
obj = re.compile("window.userAvatar = '(.*)';")
src = obj.findall(rep.text)[0]
res_dict["code"] = 201
res_dict["img"] = src return HttpResponse(json.dumps(res_dict))
elif "window.code=200;" in rep.text:
# 确定登陆
obj = re.compile('window.redirect_uri="(.*)";')
url = obj.findall(rep.text)[0]
res_dict["code"] = 200
res_dict["url"] = url
new = requests.get(url = url + "&fun=new&version=v2&lang=zh_CN")
script_obj = BeautifulSoup(new.text,"html.parser")
temp_dict = {}
for tag in script_obj.find(name="error"):
temp_dict[tag.name] = tag.text request.session["temp_dict"] = temp_dict
request.session["cookies"] = new.cookies.get_dict()
return HttpResponse(json.dumps(res_dict))
else:
pass
return HttpResponse("haha") def index(request):
url = "https://wx2.qq.com/cgi-bin/mmwebwx-bin/webwxinit?r=-221192329&pass_ticket={t}".format(t = request.session["temp_dict"].get("pass_ticket"))
init = requests.post(
url=url,
json={
"BaseRequest":{
"DeviceID":"e701447882725714",
"Sid":request.session["temp_dict"].get("wxsid"),
"Skey":request.session["temp_dict"].get("skey"),
"Uin":request.session["temp_dict"].get("wxuin")
}
}
)
init.encoding = "utf-8"
init_user_dict = init.json()
return render(request,"index.html",locals()) def contact(request):
t = int(time.time() * 1000)
rep = requests.get(
url = "https://wx2.qq.com/cgi-bin/mmwebwx-bin/webwxgetcontact?lang=zh_CN&pass_ticket={p}&r={t}&seq=0&skey={s}".format(t = t,
p = request.session["temp_dict"]["pass_ticket"],
s = request.session["temp_dict"]["skey"]),
cookies = request.session["cookies"]
)
rep.encoding = "utf-8"
user_list= rep.json() return render(request,"contact.html",locals()) def avator(request):
# print(request.GET.get("prev"))
# print(request.GET.get("username"))
# print(request.GET.get("skey"))
url = "https://wx2.qq.com{p}&username={u}&skey={s}".format(p = request.GET.get("prev"),
u = request.GET.get("username"),
s = request.GET.get("skey")
)
img = requests.get(
url = url,
cookies = request.session["cookies"]
)
print(url)
return img.content def sendmsg(request):
if request.method == "GET":
return render(request,"sendmsg.html") else:
from_user = request.POST.get("from_user")
to_user = request.POST.get("to_user")
content = request.POST.get("content") data_dict = {
"BaseRequest":{
"DeviceID":"e461335461567419",
"Sid":request.session["temp_dict"].get("wxsid"),
"Skey":request.session["temp_dict"].get("skey"),
"Uin":request.session["temp_dict"].get("wxuin")
},
"Msg":{
"ClientMsgId":int(time.time() * 1000),
"Content":content,
"FromUserName":from_user,
"LocalID":int(time.time() * 1000),
"ToUserName":to_user,
"Type":1
},
"Scene":0
}
rep = requests.post(
url= "https://wx2.qq.com/cgi-bin/mmwebwx-bin/webwxsendmsg?lang=zh_CN&pass_ticket={p}".format(p = request.session["temp_dict"]["pass_ticket"]), # 1、方式1,处理不了中文,由于json的问题
# json=data_dict # 2、方式2,解决了json处理不了中文的问题,但是微信用的解码是不是常见的解码方式,所以还是处理不了中文
# data = json.dumps(
# data_dict,
# ensure_ascii=False
# ) # 3、方式3,直接发送二进制文件,就可以解决发送中文的问题
data = bytes(json.dumps(
data_dict,
ensure_ascii=False
),encoding="utf-8")
)
print(rep.text) return HttpResponse("success")

  

相信如果大家看懂我前面分析web微信的逻辑,看懂应该不成问题。如果有不清楚的,请评论留言,感谢大家关注,谢谢!

requests+django+bs4实现一个web微信的功能的更多相关文章

  1. Django的第一个web程序及深入学习

    本学习历程参照Practical Django Projects和http://djangobook.py3k.cn上翻译的内容进行 注:本例以本机加以说明: 根据Django的安装过程可知:在命令行 ...

  2. Web微信模拟

    一.概要 目的:实现一个具有web微信类似功能的项目 框架:Django 模块:render.HttpResponse.BeautifulSoup.re.time.requests.json.rand ...

  3. Python 爬虫五 进阶案例-web微信登陆与消息发送

    首先回顾下网页微信登陆的一般流程 1.打开浏览器输入网址 2.使用手机微信扫码登陆 3.进入用户界面 1.打开浏览器输入网址 首先打开浏览器输入web微信网址,并进行监控: https://wx.qq ...

  4. web 框架的本质及自定义web框架 模板渲染jinja2 mvc 和 mtv框架 Django框架的下载安装 基于Django实现的一个简单示例

    Django基础一之web框架的本质 本节目录 一 web框架的本质及自定义web框架 二 模板渲染JinJa2 三 MVC和MTV框架 四 Django的下载安装 五 基于Django实现的一个简单 ...

  5. CentOS 7.0 部署 Django 到运行起来第一个web service

    最近在学习Python,今天发现Django如此强大的web框架,不得不来试一试. 1. 安装Python,官网建议用Python3:

  6. Pycharm+Django搭建第一个Python Web程序

    1.安装django 无论是Python2.x还是Python3.x版本,都可以使用pip来安装Django.在控制台使用如下命令:pip install django 如: 2.检查dgango是否 ...

  7. Anaconda+django写出第一个web app(十)

    今天继续学习外键的使用. 当我们有了category.series和很多tutorials时,我们查看某个tutorial,可能需要这样的路径http://127.0.0.1:8000/categor ...

  8. Anaconda+django写出第一个web app(一)

    在安装好Anaconda和django之后,我们就可以开始创建自己的第一个Web app,那么首先创建一个空文件夹,之后创建的文件都在这个文件夹内. 启动命令行进入此文件夹内,可以先通过如下命令查看一 ...

  9. Django学习笔记之Web框架由浅入深和第一个Django实例

    Web框架本质 我们可以这样理解:所有的Web应用本质上就是一个socket服务端,而用户的浏览器就是一个socket客户端. 这样我们就可以自己实现Web框架了. 半成品自定义web框架 impor ...

随机推荐

  1. altera DDR2 ip使用笔记之IP核生成

    IP核生成 Quartus生成DDR2 ip流程如下: 点击菜单栏的Tools->MegaWizard Plug-In Manager,弹出  选择IP类型,保持路径即文件名等,如下图  点击n ...

  2. 树莓派做下载服务器 aria2 篇

    一开始要运行一下配置,扩大树莓派的根目录的空间,不然所有软件装完之后空间会只剩几百兆. sudo raspi-config 扩展根目录空间, 开启 SSH ,修改 pi 密码. 另外要提一下,树莓派默 ...

  3. 常见手机的设备分辨率、viewport和devicePixelRatio

    常见手机的设备分辨率和viewport分辨率,及其1rem的大小(以vmin为单位) 常见的devicePixelRatio是1, 1.325, 1.5, 2, 2.4, 3.  (具体见下面的表格, ...

  4. Java Base64位加密和解密(包括其他加密参考)

    链接https://blog.csdn.net/longguangfu8/article/details/78948213 常用加密解密算法[RSA.AES.DES.MD5]介绍和使用 https:/ ...

  5. java锁

    ---恢复内容开始--- synchronized 互斥锁 synchronized(this) 当前类的所有synchronized(this) 都被锁了,还有synchronized static ...

  6. LayaAir疑难杂症之三:1.7版本click()、execCommand('copy')函数不生效

    问题描述 在使用Laya1.7引擎开发H5游戏时,引入Js原生函数click( ),模拟一次点击事件,发现无效.在使用Laya1.7引擎开发H5游戏时,引入Js原生函数execCommand('cop ...

  7. java 导出 excel 最佳实践,java 大文件 excel 避免OOM(内存溢出) excel 工具框架

    产品需求 产品经理需要导出一个页面的所有的信息到 EXCEL 文件. 需求分析 对于 excel 导出,是一个很常见的需求. 最常见的解决方案就是使用 poi 直接同步导出一个 excel 文件. 客 ...

  8. redis--解析字符串

    # coding=utf-8import codecs if __name__ == '__main__': cmdlist = ("Decode") while True: cm ...

  9. 值得推荐的五大敏捷PHP开发框架

    各位开发者,对于在HTML中混乱使用PHP的人来说,我们给大家推荐几款PHP敏捷开发的框架,以及它们为什么能够流行. 在我们开始之前,先了解敏捷开发是个什么东东. 敏捷是一种软件开发方法,每次开发计划 ...

  10. 深入理解Java虚拟机读书笔记3----类文件结构

    三 类文件结构 1 Java虚拟机的两种中立特性     · 平台无关性     · 语言无关性     实现平台无关性和语言无关性的基础是虚拟机和字节码存储格式(Class文件).   2 Clas ...