前言:

  今天我们利用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. spring从服务器磁盘读取图片,然后显示于前端页面上

    需求是,前台通过传参,确定唯一图片,然后后台在服务器磁盘中读取该图片,然后显示于前台页面上. 后台代码: @RequestMapping("unit/bill/showeinvoice&qu ...

  2. mysql通过now()获取的时间不对

    先用now()获取系统时间,发现时间不对(差8个小时): mysql> select now(); +---------------------+ | now() | +------------ ...

  3. 软件测试:3.Exercise Section 2.3

    软件测试:3.Exercise Section 2.3 /************************************************************ * Finds an ...

  4. BAT开发中,ChromeDriver版本兼容性检查

    打开解决方案的Nuget包管理器,选择合适的版本,安装即可.版本的兼容性检查,见上一篇blog(初次使用BAT,请检查Chrome浏览器和ChromeDriver兼容性 https://www.cnb ...

  5. PADS导入DXF板框,不能将开放的2D线转换成闭合的板框错误

    刚开始学会用PADS,学习的时候都是在PADS里手绘一个板框的.然后实际项目中,都是需要导入结构DXF板框文件,第一次导入就发现了问题. 第一次导入DXF后,需要将DXF转换为板框,但提示 “不能将开 ...

  6. FTP学习笔记

    FTP有两个连接方式 1.控制连接 2.数据连接 控制链接 标准端口为21  用于数据传输中的控制 数据连接 标准端口20  用于数据传输中的上传 下载数据 数据传输的连接方式,主动连接 被动连接. ...

  7. 团队第六次 # scrum meeting

    github 本此会议项目由PM召开,召开时间为4-10日晚上9点 召开时长20分钟 任务表格 袁勤 负责协调前后端 https://github.com/buaa-2016/phyweb/issue ...

  8. Error occurred during initialization of VM Could not reserve enough space for object heap

    Error occurred during initialization of VM Could not reserve enough space for object heap Java虚拟机(JV ...

  9. [java,2017-05-17] 数据型参数趣谈

    int的最大值是多少?加一呢?乘2呢? 第一个问题我想大多数人都知道,不知道后两个有多少人研究过. 首先上一段代码: public class DecimalTest { public static ...

  10. zabbix解决监控图中出现中文乱码问题

    首先确定zabbix开启了中文支持功能:登录到zabbix服务器的数据目录下(前面部署的zabbix数据目录是/data/www/zabbix),打开 locales.inc.php文件[root@Z ...