基于flask的web微信
web微信
1.扫码获取头像
当你打开web微信的时候,因为http是无状态的,web微信如何实时的获取用户的扫码动作?
那么这里用到的是长轮询的方式。
from flask import Flask,request,redirect,render_template,session,jsonify
import time
import requests
import re
from bs4 import BeautifulSoup
import json app =Flask(__name__)
app.secret_key='adfa12da' @app.route('/login',methods=['GET',"POST"])
def login():
'''
扫码获取头像
:return:
'''
if request.method=='GET':
ctime = str(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)
ret = requests.get(qcode_url)
qcode = re.findall('uuid = "(.*)";',ret.text)[0]
session['qcode'] = qcode
session['login_cookies'] = ret.cookies.get_dict()
return render_template('login.html',qcode=qcode) else:
pass ####Html#########
<img id="img" src="https://login.weixin.qq.com/qrcode/{{qcode}}">
获取web微信头像
2.点击登录
a.当扫码成功后获取到了web头像,依旧要执行长轮询,我们需要做的是获取发起长轮询的url,
b.将登录成功的cookies保存在session里。
c.模仿浏览器自动访问并且挂起。当登录成功后,状态码为200,跳转到主页面
@app.route('/check_login',methods=['GET','POST'])
def check_login():
'''
检测是否已经登录.
url:https://login.wx.qq.com/cgi-bin/mmwebwx-bin/login?loginicon=true&uuid=AcjVHfghyA==&tip=0&r=-557419402&_=1529565723654
:return:
'''
if request.method=='GET':
response= {'code':408}
qcode = session.get('qcode')
ctime = str(int(time.time()*1000))
check_url = 'https://login.wx.qq.com/cgi-bin/mmwebwx-bin/login?loginicon=true&uuid={0}&tip=0&r=-557419402&_={1}'.format(qcode,ctime)
ret = requests.get(url=check_url)
print(ret.text)
if 'code=201' in ret.text:
src = re.findall("userAvatar = '(.*)';",ret.text)[0]
response['code']=201
response['src'] = src
elif 'code=200' in ret.text:
src = re.findall('redirect_uri="(.*);',ret.text)[0]
response['code']=200
response['src']=src
ret = requests.get(url=src+'&fun=new&version=v2&lang=zh_CN')
xml_dic = xml_parser(ret.text)
session['xml_dic']=xml_dic
session['pass_cookies'] = ret.cookies.get_dict()
print(xml_dic)
return jsonify(response)
####js代码####
#不断的发送长轮询 当返回的状态码为200的时候跳转页面
$(function () {
check_login();
});
function check_login() {
$.ajax({
url:'/check_login',
type:'GET',
datatype:'JSON',
success:function (arg) {
if (arg.code == 201){
$('#img').attr('src',arg.src);
check_login();
}
else if (arg.code == 200){
location.href='/index'
}else {
check_login();
}
}
})
}
登录成功
3.获取个人信息和联系人列表
a.当登录成功后,进行获取个人的信息,存放在session里方便后面的使用。
b.获取联系人列表在前端展示.
@app.route('/index',methods=['GET',"POST"])
def index():
pass_ticket =session['xml_dic'].get('pass_ticket')
inni_dic={
'BaseRequest':{
'DeviceID':"e901523268059245",
'Sid':session['xml_dic'].get('wxsid'),
'Skey':session['xml_dic'].get('skey'),
'Uin':session['xml_dic'].get('wxuin'),
}
}
inni_msg = requests.post(
url ='https://wx2.qq.com/cgi-bin/mmwebwx-bin/webwxinit?r=-581032482&lang=zh_CN&pass_ticket={0}'.format(pass_ticket),
json=inni_dic
)
inni_msg.encoding='utf-8'
user_dict = inni_msg.json()
session['user_info'] = user_dict['User']
session['SyncKey'] = user_dict['SyncKey']
ctime= str(int(time.time()*1000))
contact_url= 'https://wx2.qq.com/cgi-bin/mmwebwx-bin/webwxgetcontact?lang=zh_CN&pass_ticket={0}&r={1}&seq=0&skey={2}'
contact_url = contact_url.format(pass_ticket,ctime,session['xml_dic'].get('skey'))
pass_cookies = session.get('pass_cookies')
contact_list = requests.get(
url=contact_url,
cookies = pass_cookies,
)
contact_list.encoding = 'utf-8'
result_list = contact_list.json()
return render_template('index.html',user_dict=user_dict,result_list=result_list)
####前端代码####
<body>
<h1>Welcome {{user_dict.User.NickName}}!!</h1>
<img src="/get_img" alt="">
<ul>
{%for row in user_dict.ContactList%}
<li>{{row.NickName}}</li>
{%endfor%}
</ul>
<div>
<h1>全部联系人</h1>
<ul>
{% for item in result_list.MemberList%}
<li>{{item.UserName}}===={{item.NickName}}</li>
{%endfor%}
</ul>
</div>
</body>
4.登录成功后获取头像
#<img src="/get_img" alt="">
@app.route('/get_img',methods=['GET','POST'])
def get_img():
# 需要不断的试cookies
# 登录以后的操作一般都需要cookies, 一般cookies是拿登录成功后的
# 特殊的需要将cookies成功之后才能进行登录,访问的时候就记录cookies
# headers的重要参数: Referer host User_Agent
user_info = session.get('user_info')
pass_cookies = session.get('pass_cookies')
header_url = "https://wx2.qq.com"+user_info['HeadImgUrl']
ret = requests.get(
url = header_url,
cookies = pass_cookies,
headers= {
'Content-Type': 'image/jpeg',
}
)
return ret.content
5.发送信息
登录成功后,拿到了联系人列表,其中返回的信息里面的MemberList有每个人的NickName.
用Ajax给他人发送消息
@app.route('/send_msg',methods=['GET','POST'])
def send_msg():
if request.method=='GET':
return 'what are you 弄啥呢'
else:
data =request.form
to = data.get('to')
content = data.get('content')
print(to,content)
user = session['user_info']['UserName']
pass_ticket =session['xml_dic'].get('pass_ticket')
ctime= str(int(time.time()*1000))
send_url ='https://wx2.qq.com/cgi-bin/mmwebwx-bin/webwxsendmsg?lang=zh_CN&pass_ticket={0}'.format(pass_ticket)
send_dict = {
'BaseRequest':{
'DeviceID': "e901523268059245",
'Sid': session['xml_dic'].get('wxsid'),
'Skey': session['xml_dic'].get('skey'),
'Uin': session['xml_dic'].get('wxuin'),
},
'Msg':{'ClientMsgId':ctime,
'LocalID':ctime,
'FromUserName':user,
'ToUserName':to,
'Type':1,
'Content':content,
},
'Scene':0,}
ret = requests.post(
url=send_url,
data=bytes(json.dumps(send_dict,ensure_ascii=False),encoding='utf-8'),
)
return ret.text
###前端代码####
<body>
<form id="fm">
<input type="text" name="to" placeholder="联系人">
<input type="text" name="content" placeholder="内容">
<button onclick="send_msg();">提交</button>
</form>
function send_msg() {
$.ajax({
url:'/send_msg',
data:$('#fm').serialize(),
type:'POST',
dataType:'JSON',
success:function (arg) {
if (arg.BaseResponse.Ret == 0){
console.log('发送成功');
$('#fm').find(':input').val('')
}
}
})
}
发送信息
json.dumps需要注意的问题
json.dumps需要注意的问题
6.接收信息
接收消息也是不断的向服务端发送请求,检查是否有人发送消息
@app.route('/get_msg',methods=['GET','POST'])
def get_msg():
user_init_list = session.get('SyncKey').get('List')
syn_list=[]
for item in user_init_list:
temp = '%s_%s'%(item['Key'],item['Val'])
syn_list.append(temp)
syn_list_str = '|'.join(syn_list)
get_url = 'https://webpush.wx2.qq.com/cgi-bin/mmwebwx-bin/synccheck'
ctime = str(int(time.time() * 1000))
syn_dict={
'r':ctime,
'DeviceID': "e901523268059245",
'Sid': session['xml_dic'].get('wxsid'),
'Skey': session['xml_dic'].get('skey'),
'Uin': session['xml_dic'].get('wxuin'),
'synckey':syn_list_str
}
all_cookies={}
all_cookies.update(session['login_cookies'])
all_cookies.update(session['pass_cookies'])
response = requests.get(
url=get_url,params=syn_dict,cookies=all_cookies
)
print(response.text)
if 'selector:"2"' in response.text:
data = {
'BaseRequest': {
'DeviceID': "e901523268059245",
'Sid': session['xml_dic'].get('wxsid'),
'Skey': session['xml_dic'].get('skey'),
'Uin': session['xml_dic'].get('wxuin'),
},
'synckey': session.get('SyncKey'),
'rr': ctime,
}
url = 'https://wx2.qq.com/cgi-bin/mmwebwx-bin/webwxsync?sid={0}&skey={1}'.format(session['xml_dic'].get('wxsid'),
session['xml_dic'].get('skey'), )
response_msg = requests.post(
url=url,json=data
)
response_msg.encoding = 'utf-8'
response_msg_dic = response_msg.json()
session['SyncKey'] = response_msg_dic['SyncKey']
for item in response_msg_dic:
print(item['Content'],'=========>',item['FromUserName'],'========',item['ToUserName'])
return 'pass'
#######前端#######
$(function () {
get_msg();
});
function get_msg() {
$.ajax({
url:'/get_msg',
type:'GET',
success:function (arg) {
if (arg){
get_msg();
}
}
})
}
轮询
轮询:
浏览器每一段时间(2s)向浏览器发一次请求,检查用户是否扫码.
浏览器发的url主要是检验用户是否扫码,只要扫码就返回头像 缺点:不断的向服务器发请求,服务器的内存压力大, 效率低,存在时间差 长轮询:
浏览器在像web微信服务器发请求的时候,没有立即断开而是挂在那里,一直连接着,
最多连接30秒,自动断开后,又马上挂起一个请求
只要用户一扫码服务器就可以马上检测到.
高性能
高性能相关:
开进程->单线程
本质:
浏览器本质:1.socket客户端遵循HTTP协议
2.http协议建立在tcp协议之上
3.规定了发送的时候的数据格式 \r\n\r\n
4.短连接,无状态
协程
协程是'微线程',真实是不存在的,是程序员人为创造出来并控制程序先执行段代码,再执行某段代码.
-如果遇到非IO请求就切换,性能低.
-如果遇到IO请求切换,性能高.能够实现并发(IO等待的过程,再去干其他的事)
IO多路复用
select: 内部循环监听多个socket对象是否发生状态的变化 最多1024个
poll: 内部循环监听多个socket对象是否发生状态的变化
epoll: 回调的方式 通过硬件和操作系统
基于flask的web微信的更多相关文章
- 基于Flask 实现Web微信登陆
网页版微信登陆网址 https://login.wx.qq.com/ 获取微信登陆的二维码 在浏览器中访问登陆接口 https://login.wx.qq.com/ 我们查找二维码的图片可以看到 其中 ...
- 基于Flask开发web微信
1. 获取二维码 app.py import re import time import requests from flask import Flask,render_template app = ...
- 树莓派搭建基于flask的web服务器-通过移动端控制LED
1.概述 在局域网内,基于flask搭建web服务,从而可以使用移动客户端访问该web服务.由于是flask新手,所以本次实现的web服务功能较为简单,即控制LED灯的开/关及闪烁. 2.准备工作 2 ...
- 基于Flask的Web应用程序插件式结构开发
事实上,很多应用程序基于插件式结构开发,可以很方便了扩展软件的功能,并且这些功能完全可以依托于第三方开发者,只要提供好接口和完备文档,比如wordpress.谷歌火狐浏览器等. Python这样的动态 ...
- 基于Flask的Web应用部署到SAE上遇到的问题
我的应用底层数据库用的是MySQL,利用Flask-SQLALchemy实现接口操作.我遇到的问题是: 在我把代码部署到SAE上后,当数据向数据库insert的时候总是出现“2006,MySQL ha ...
- 基于Flask实现博客开发--准备工作
背景说明 本项目是基于<深入理解flask>一书,主要是用来记录学习历程和交流心得,所以写得不好请大神勿喷. 准备工作 virtualenv介绍 也许 Virtualenv 是你在开发中最 ...
- SZhe_Scan碎遮:一款基于Flask框架的web漏洞扫描神器
SZhe_Scan碎遮:一款基于Flask框架的web漏洞扫描神器 天幕如遮,唯我一刀可碎千里华盖,纵横四海而无阻,是谓碎遮 --取自<有匪> 写在前面 这段时间很多时间都在忙着编写该项目 ...
- Python flask 基于 Flask 提供 RESTful Web 服务
转载自 http://python.jobbole.com/87118/ 什么是 REST REST 全称是 Representational State Transfer,翻译成中文是『表现层状态转 ...
- 《Flask Web开发——基于Python的Web应用开发实践》一字一句上机实践(上)
目录 前言 第1章 安装 第2章 程序的基本结构 第3章 模板 第4章 Web表单 第5章 数据库 第6章 电子邮件 第7章 大型程序的结构 前言 学习Python也有一个半月时间了,学到现在感觉 ...
随机推荐
- 比特币Bitcoin-qt客户端加密前后如何导入导出私钥?
一.Bitcoin-qt客户端加密后 如需要导出某一地址对应的私钥,需要先调用 walletpassphrase 密码 解锁持续时间(秒), 如:walletpassphrase h123456789 ...
- Spring声明式事务的配置方式
1.事务的特性 原子性:事务中的操作是不可分割的一部分 一致性:要么同时成功,要么同时失败(事务执行前后数据保持一致) 隔离性:并发互不干扰 持久性:事务一旦被提交,它就是一条持久 ...
- JMeter接口测试中文乱码问题总结
在测试过程中遇到了请求json串中文乱码,所以查看了这篇文章,将字符集修改后,乱码问题已经处理. 转载http://blog.csdn.net/qing_java/article/details/69 ...
- 【OpenGL 学习笔记01】HelloWorld演示样例
<<OpenGL Programming Guide>>这本书是看了忘,忘了又看,赶脚还是把笔记做一做心里比較踏实,哈哈. 我的主题是,好记性不如烂笔头. ========== ...
- 块设备驱动之NOR FLASH驱动
转载请注明出处:http://blog.csdn.net/ruoyunliufeng/article/details/25240947 一.硬件原理 从原理图中我们能看到NOR FLASH有地址线,有 ...
- python——Container之字典(dict)详解
字典(dictionary)是除列表以外python之中最灵活的内置数据结构类型.列表是有序的对象结合,字典是无序的对象集合.两者之间的区别在于:字典当中的元素是通过键来存取的,而不是通过偏移存取. ...
- react-native 项目实战 -- 新闻客户端(7) -- 新闻详情页
http://c.3g.163.com/nc/article/BUH64L0J00031H2L/full.html 观察这个地址,BUH64L0J00031H2L 就是每条新闻数据里的postid. ...
- C++ 模板详解(二)(转)
四.类模板的默认模板类型形参 1.可以为类模板的类型形参提供默认值,但不能为函数模板的类型形参提供默认值.函数模板和类模板都可以为模板的非类型形参提供默认值. 2.类模板的类型形参默认值形式为:tem ...
- JS 手势长按代码
同时支持长按和点击事件,无依赖版 <!DOCTYPE html> <html lang="en"> <head> <meta charse ...
- Linux系统下如何监测磁盘的使用空间
不管是我们在安装软件还是监测软件的使用性能,我们都要随时掌握系统磁盘的使用情况. 使用df命令 df df命令用于显示磁盘分区上的可使用的磁盘空间.默认显示单位为KB.可以利用该命令来获取硬盘被占用了 ...