基于Flask开发web微信
1. 获取二维码
app.py
import re
import time
import requests
from flask import Flask,render_template app = Flask(__name__)
app.secret_key = '1231sdfasdf'
@app.route('/login')
def login():
# 1529982725262
# 15299828432250135
ctime = int(time.time() * 1000)
qcode_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&_={0}".format(ctime) rep = requests.get(
url=qcode_url
)
# print(rep.text) # window.QRLogin.code = 200; window.QRLogin.uuid = "gb8UuMBZyA==";
qcode = re.findall('uuid = "(.*)";',rep.text)[0]
session['qcode'] = qcode
return render_template('login.html',qcode = qcode)
if __name__ == '__main__': app.run()
login.html
<body>
<div style="width: 200px;margin: 0 auto;">
<h1 style="text-align: center;">扫码登录</h1>
<img style="width: 200px;height: 200px;" src="https://login.weixin.qq.com/qrcode/{{qcode}}" alt="">
</div>
</body>
2. 检查登录:扫码
1、登陆的时候需要长连接,一直保持opening的状态
2、因为第一次访问页面的时间仍然需要用到,不能用g(一次请求己结束),选择用session获取的方式
from bs4 import BeautifulSoup def xml_parse(text):
result = {}
soup = BeautifulSoup(text,'html.parser')
tag_list = soup.find(name='error').find_all()
for tag in tag_list:
result[tag.name] = tag.text
return result
@app.route('/check/login')
def check_login(): qcode = session['qcode']
ctime = int(time.time() * )
check_login_url = 'https://login.wx.qq.com/cgi-bin/mmwebwx-bin/login?loginicon=true&uuid={0}&tip=0&r=-976036168&_={1}'.format(qcode,ctime) rep = requests.get(
url=check_login_url
)
result = {'code': } if 'window.code=408' in rep.text:
# 用户未扫码
result['code'] =
elif 'window.code=201' in rep.text:
# 用户扫码,获取头像
result['code'] =
result['avatar'] = re.findall("window.userAvatar = '(.*)';",rep.text)[]
elif 'window.code=200' in rep.text:
# 用户确认登录
redirect_uri = re.findall('window.redirect_uri="(.*)";',rep.text)[]
print(redirect_uri)
#https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxnewloginpage?ticket=ASEHe9Kr5Hq0PITHG1dXEBS8@qrticket_0&uuid=gfbq6fFg9Q==&lang=zh_CN&scan=1529986929&fun=new&version=v2
# https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxnewloginpage?ticket=ATEkrWXwLgR3QjDuYsx-dpzN@qrticket_0&uuid=obFFB7YwVA==&lang=zh_CN&scan=1529986454
redirect_uri = redirect_uri + "&fun=new&version=v2"
ru = requests.get(url=redirect_uri) # <error><ret></ret><message></message><skey>@crypt_ac8812af_0ffde1190007c7c044bc31ae51407c45</skey><wxsid>fRwfacRtjRFpEIwt</wxsid><wxuin></wxuin><pass_ticket>0M1plebTzNQ%2FKaSIfTfk65laCSXUWmjpxvJEerZSnBaEDjNIyOafaQLtpQBhnCDa</pass_ticket><isgrayscale></isgrayscale></error>
ticket_dict = xml_parse(ru.text)
session['ticket_dict'] = ticket_dict
result['code'] = return jsonify(result)
获取头像201,登录认证200
<body>
<div style="width: 200px;margin: 0 auto;">
<h1 style="text-align: center;">扫码登录</h1>
<img id="userAvatar" style="width: 200px;height: 200px;" src="https://login.weixin.qq.com/qrcode/{{qcode}}" alt="">
</div> <script src="https://cdn.bootcss.com/jquery/3.3.0/jquery.min.js"></script>
<script>
$(function () {
checkLogin();
});
function checkLogin() {
$.ajax({
url:'/check/login',
method:'GET',
dataType:'json',
success:function (arg) {
console.log(arg);
checkLogin();
if(arg.code === ){
checkLogin();
}else if(arg.code === ){
$('#userAvatar').attr('src',arg.avatar);
checkLogin();
}else if(arg.code === ){
location.href = "/index"
}
}
})
}
</script>
</body>
3. 检查登录:确认登录
同上
4. 获取凭证:redirect_uri
同上
"""
import re
data = 'window.QRLogin.code = 200; window.QRLogin.uuid = "gb8UuMBZyA==";'
ret = re.findall('uuid = "(.*)";',data)[]
print(ret)
""" from bs4 import BeautifulSoup def xml_parse(text):
result = {}
soup = BeautifulSoup(text,'html.parser')
tag_list = soup.find(name='error').find_all()
for tag in tag_list:
result[tag.name] = tag.text
return result v = "<error><ret>0</ret><message></message><skey>@crypt_ac8812af_0ffde1190007c7c044bc31ae51407c45</skey><wxsid>fRwfacRtjRFpEIwt</wxsid><wxuin>1062220661</wxuin><pass_ticket>0M1plebTzNQ%2FKaSIfTfk65laCSXUWmjpxvJEerZSnBaEDjNIyOafaQLtpQBhnCDa</pass_ticket><isgrayscale>1</isgrayscale></error>"
result = xml_parse(v) # print(result) print(round(1.4))
5. 信息初始化:
- 联系人
- 公众号
6. 获取所有联系人
@app.route('/index')
def index():
pass_ticket = session['ticket_dict']['pass_ticket']
init_url = "https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxinit?r=-979112921&lang=zh_CN&pass_ticket={0}".format(pass_ticket) rep = requests.post(
url=init_url,
json={
'BaseRequest':{
'DeviceID':"e700290354098676",
'Sid':session['ticket_dict']['wxsid'],
'Skey':session['ticket_dict']['skey'],
'Uin':session['ticket_dict']['wxuin'],
}
}
)
rep.encoding = 'utf-8' init_user_dict = rep.json()
print(init_user_dict) return render_template('index.html',init_user_dict=init_user_dict)
index.html
<body>
<h1>欢迎使用Web微信:{{init_user_dict.User.NickName}}</h1> <h3>最近联系人</h3>
<ul>
{% for row in init_user_dict.ContactList %}
<li>{{row.NickName}}</li>
{% endfor %}
<li><a href="#">查看所有联系人</a></li>
</ul> <h3>最近公众号</h3>
{% for item in init_user_dict.MPSubscribeMsgList %}
<div>
<h3>{{item.NickName}}</h3>
<ul>
{% for msg in item.MPArticleList %}
<li><a href="{{msg.Url}}">{{msg.Title}}</a></li>
{% endfor %}
</ul>
</div>
{% endfor %} </body>
7. 获取联系人列表
1、
@app.route('/contact/list')
def contack_list():
"""
获取联系人列表
:return:
"""
# https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxgetcontact?lang=zh_CN&pass_ticket=Q4pDjGjjdjOnFwfHS5I3XFzFc4ApHkTaKzlCOdh34uTVavWegV%252BUky37VviDufnO&r=1530064956758&seq=0&skey=@crypt_2ccf8ab9_fbbb31c98b1a1c12b4ec707678dd336e
# GET
ctime = int(time.time() * )
pass_ticket = session['ticket_dict']['pass_ticket']
skey = session['ticket_dict']['skey']
contact_url = "https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxgetcontact?lang=zh_CN&pass_ticket={0}&r={1}&seq=0&skey={2}".format(pass_ticket,ctime,skey) res = requests.get(
url=contact_url,
cookies=session['ticket_cookies']
)
res.encoding = 'utf-8'
user_list = res.json() return render_template('contact_list.html',user_list=user_list)
contact_list.html
<body>
<h1>联系人列表</h1>
<ul>
{% for user in user_list.MemberList %}
<li>
<img style="height: 50px;width: 50px;" src="/get_img?prev={{user.HeadImgUrl}}">
<span>用户名:{{user.NickName}} 唯一标识:{{user.UserName}}</span>
</li>
{% endfor %} </ul>
</body>
在获取用户图片
@app.route('/get_img')
def get_img():
prev = request.args.get('prev') # /cgi-bin/mmwebwx-bin/webwxgeticon?seq=
username = request.args.get('username') # @9c4df5e041eb06725a410a3d9d580877e229066895b3e91d44a7af8be37e0e5b
skey = request.args.get('skey') # @crypt_ac8812af_a5601beadce3211cdb4fd3663d08ab52 head_img_url = "https://wx.qq.com{0}&username={1}&skey={2}".format(prev,username,skey) rep = requests.get(
url=head_img_url,
cookies=session['ticket_cookies']
) return rep.content
8. 发送消息
@app.route('/send/msg',methods=['GET','POST'])
def send_msg():
if request.method == "GET":
return render_template('send_msg.html') ctime = int(time.time() * )
from_user = request.form.get('fromUser')
to_user = request.form.get('toUser')
content = request.form.get('content') data_dict = {
'BaseRequest':{
'DeviceID':"e700290354098676",
'Sid':session['ticket_dict']['wxsid'],
'Skey':session['ticket_dict']['skey'],
'Uin':session['ticket_dict']['wxuin'],
},
'Msg':{
'ClientMsgId':ctime,
'Content':content,
'FromUserName':from_user,
'LocalID':ctime,
'ToUserName':to_user,
'Type':
},
'Scene':
} msg_url = "https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxsendmsg?lang=zh_CN&pass_ticket={0}".format(session['ticket_dict']['pass_ticket'])
rep = requests.post(
url=msg_url,
data=bytes(json.dumps(data_dict,ensure_ascii=False),encoding='utf-8')
) print(rep) return "发送成功"
send_msg.html
@app.route('/send/msg',methods=['GET','POST'])
def send_msg():
if request.method == "GET":
return render_template('send_msg.html') ctime = int(time.time() * )
from_user = request.form.get('fromUser')
to_user = request.form.get('toUser')
content = request.form.get('content') data_dict = {
'BaseRequest':{
'DeviceID':"e700290354098676",
'Sid':session['ticket_dict']['wxsid'],
'Skey':session['ticket_dict']['skey'],
'Uin':session['ticket_dict']['wxuin'],
},
'Msg':{
'ClientMsgId':ctime,
'Content':content,
'FromUserName':from_user,
'LocalID':ctime,
'ToUserName':to_user,
'Type':
},
'Scene':
} msg_url = "https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxsendmsg?lang=zh_CN&pass_ticket={0}".format(session['ticket_dict']['pass_ticket'])
rep = requests.post(
url=msg_url,
data=bytes(json.dumps(data_dict,ensure_ascii=False),encoding='utf-8')
) print(rep) return "发送成功"
9、使用
使用发送信息的时候、需要先获取用户当前的UserName,在第一次获取index.html时
print(init_user_dict)里去网页json解析出来即可使用,注意每次登录的username里的符号都会变化
'User': {
'Uin': ,
'UserName': '@586d71fe149ae1942bc5bca1f64edd87d385b449850bdc6796ade1a92c9d2933',
10、总结
发送data和json的区别
关系发送消息:
data:
request.post(
url='xx',
data={'k1':'v1,'k2':'v2'}
)
#数据: POST / http1.\r\n....\r\n\r\nk1=v1&k2=v2 request.post(
url='xx',
data=json.dumps({'k1':'v1,'k2':'v2'})
)
#数据: POST / http1.\r\n....\r\n\r\n{'k1':'v1,'k2':'v2'} request.post(
url='xx',
data=b'asdfasdf'
)
#数据: POST / http1.\r\n....\r\n\r\n'asdfasdf'
json:
request.post(
url='xx',
json={'k1':'v1,'k2':'v2'}
)
#数据: POST / http1.\r\nContent-type:application/json....\r\n\r\n{'k1':'v1,'k2':'v2'} 问题:
同时:POST请求发数据 django:获取不到值?request.POST 发送数据格式:
方式一:
request.post(
url='xx',
data={'k1':'v1,'k2':'v2'}
)
#数据: POST / http1.\r\nContent-type:urlencode-form.......\r\n\r\nk1=v1&k2=v2 request.POST必然可以获取到值。
- content-type: urlencode-form
- 数据格式:k1=v1&k2=v2 方式二:
request.post(
url='xx',
json={'k1':'v1,'k2':'v2'}
)
#数据: POST / http1.\r\nContent-type:application/json....\r\n\r\n{'k1':'v1,'k2':'v2'}
request.body
字节 = {'k1':'v1,'k2':'v2'}
字节转换字符串
反序列化字符串 -> 字典 request.POST必然不可以获取到值。
- content-type: urlencode-form
- 数据格式:k1=v1&k2=v2 知识点:
chrome->
Form Data:
phone=&password=&oneMonth= reqeusts.post(
url=url,
data={
phone:,
password:asdfasdf
}
) Request Payload:
{"BaseRequest":{"Uin":,"Sid":"zWvteTWqBop4heoT","Skey":"@crypt_2ccf8ab9_a710cf413c932e201987599558063c8e","DeviceID":"e358217921593270"},"Msg":{"Type":,"Content":"test","FromUserName":"@60eef3f2d212721fda0aae891115aa7a","ToUserName":"@@6a5403f510a3192454ed1afebd78ec6033d5057c9038d7b943b201f0a74987d4","LocalID":"","ClientMsgId":""},"Scene":} reqeusts.post(
url=url,
json={
phone:,
password:asdfasdf
}
) reqeusts.post(
url=url,
data=bytes(json.dumps({
phone:,
password:asdfasdf
}),encoding=utf-)
) firefox:
表单数据: JSON: 目标:练习分析Http请求能力
基于Flask开发web微信的更多相关文章
- 基于Flask 实现Web微信登陆
网页版微信登陆网址 https://login.wx.qq.com/ 获取微信登陆的二维码 在浏览器中访问登陆接口 https://login.wx.qq.com/ 我们查找二维码的图片可以看到 其中 ...
- 基于flask的web微信
web微信 1.扫码获取头像 当你打开web微信的时候,因为http是无状态的,web微信如何实时的获取用户的扫码动作? 那么这里用到的是长轮询的方式. from flask import Flask ...
- 树莓派搭建基于flask的web服务器-通过移动端控制LED
1.概述 在局域网内,基于flask搭建web服务,从而可以使用移动客户端访问该web服务.由于是flask新手,所以本次实现的web服务功能较为简单,即控制LED灯的开/关及闪烁. 2.准备工作 2 ...
- 基于Flask的Web应用程序插件式结构开发
事实上,很多应用程序基于插件式结构开发,可以很方便了扩展软件的功能,并且这些功能完全可以依托于第三方开发者,只要提供好接口和完备文档,比如wordpress.谷歌火狐浏览器等. Python这样的动态 ...
- 2020最新nginx+gunicorn+supervisor部署基于flask开发的项目的生产环境的详细攻略
本攻略基于ubuntu1804的版本,服务器用的华为云的服务器,python3(python2已经在2020彻底停止维护了,所以转到python3是必须的)欢迎加我的QQ6398903,或QQ群讨论相 ...
- 基于easyui开发Web版Activiti流程定制器详解(五)——Draw2d详解(一)
背景: 小弟工作已有十年有余,期间接触了不少工作流产品,个人比较喜欢的还是JBPM,因为出自名门Jboss所以备受推崇,但是现在JBPM版本已经与自己当年使用的版本(3.X)大相径庭,想升级也不太容易 ...
- 在 IBM RAD 平台上基于 JAX-WS 开发 Web Services服务器端,客户端
原文地址:https://www.ibm.com/developerworks/cn/websphere/library/techarticles/1305_jiangpl_rad/1305_jian ...
- 【转】基于easyui开发Web版Activiti流程定制器详解(一)——目录结构
题外话(可略过): 前一段时间(要是没记错的话应该是3个月以前)发布了一个更新版本,很多人说没有文档看着比较困难,所以打算拿点时间出来详细给大家讲解一下,由于本人平时要工作还要陪老婆和孩子而且还经营着 ...
- 基于Flask开发网站 -- 前端Ajax异步上传文件到后台
大家好,我是辰哥~ 辰哥最近利用空闲时间在写一个在线可视化平台,过程中也觉得一些技术还是比较有意思的,所以就以模块化的形式分享出来.如:从网页界面(前端)上传文件到服务器(后端). 放一下该模块的界面 ...
随机推荐
- RabbitMQ 队列、消息持久化
RabbitMQ的消息队列的持久化是一个很不错的功能,设置也非常简单.如下代码: 1.设置队列持久化(在声明队列的时候设置) channel.QueueDeclare(queue: "q.l ...
- 初始JSP
什么是JSP 1.JSP(Java Server Pages):在HTML中嵌入Java脚本代码 静态内容是JSP页面中的静态文本,其基本是HTML文本,与Java和JSP语法无关. 例子: 运行结果 ...
- 《python》join、守护进程、锁/信号量/事件、进程队列
一.multiprocess.process模块 1.join方法 阻塞主进程,等待子进程执行完毕再放开阻塞 import time import random from multiprocessin ...
- python 最小二乘拟合,反卷积,卡方检验
import numpy as np # from enthought.mayavi import mlab ''' ogrid[-1:5:6j,-1:5:6j] [array([[-1. ], [ ...
- Python Select模型(程序流程)(转)
缘由 之前写socket的CS模型代码,都是利用最原始的多线程方式.服务端是主线程,接到客户端的连接请求就从线程池中获取一个线程去处理整个socket连接的所有操作,虽然在连接数较短的情况下没有什么影 ...
- 一次练习 发现的问题,malloc free 无效;findfirstfile失败,writefile失败的原因
#include <windows.h> #include <stdio.h> #include <shlwapi.h> #pragma comment(lib,& ...
- Android UIAutomator 定位
AndroidUIAutomator:Android的源生测试框架的定位方式,定位速度快 一.组合定位 1.一般组合用id,class,text这三个属性会比较好一点,但也可以组合定位 2.id与te ...
- 『转』android官网翻译好的蓝牙API接口说明
Develop API Guides 连接 蓝牙 本文内容 基础知识 蓝牙权限 设置蓝牙 查找设备 查询配对的设备 发现设备 连接设备 连接为服务器 连接为客户端 管理连接 使用配置文件 供应商特定的 ...
- Android:getContext().getSystemService()
一.介绍 getSystemService是Android很重要的一个API,它是Activity的一个方法,根据传入的NAME来取得对应的Object,然后转换成相应的服务对象 二.语法 Windo ...
- 使用zabbix-java-gateway可以通过该网关来监听多个JVM
我们知道监控主机和网络性能指标情况可以使用zabbix很好解决,分析起来也很方便,Zabbix主要功能: - 自动发现服务器与网络设备 - 分布式监视以及WEB集中管理功能 - 可以无agent监视 ...