基于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也有一个半月时间了,学到现在感觉 ...
随机推荐
- SharePoint 2013 表单认证使用ASP.Net配置工具加入用户
前 言 上面一篇博客,我们了解到怎样为SharePoint 2013配置表单身份认证.可是加入用户是一个麻烦事儿:事实上,我们还能够用Asp.Net的配置工具,为SharePoint 2013加入表单 ...
- PDF如何自动滚动阅读
PDF如何自动滚动阅读 视图---页面显示---自动滚动 快捷键 Ctrl +shift+H
- Pro Tools安装图文教程
Pro Tools安装图文教程 Avid Pro Tools是Digidesign公司出品的一款音质最佳.音频制作强大的软件,能够在Mac或PC上为影片编曲.录制.编辑和混制高品质音乐或声音,生成 ...
- redux VS mobx (装饰器配合使用)
前言:redux和mobx都是状态管理器,避免父级到子级再到子子级嵌套单向数据流,可以逻辑清晰的管理更新共享数据.(刷新页面redux储蓄数据即消失) 配置使用装饰器(使用高阶函数包装你的组件): n ...
- Oracle 11g 递归+ exists运行计划的改变
有一个递归查询在10g上执行非常快,但在11g上执行不出来. SQL> select * from v$version; BANNER ----------------------------- ...
- Dungeon Master ZOJ 1940【优先队列+广搜】
Problem Description You are trapped in a 3D dungeon and need to find the quickest way out! The dunge ...
- MySQL - Show Processlist 整理(转)
原文来源:MySQL 5.5 Reference Manual 部分翻译取自:<MySQL_5.1中文参考手册> 转载请注明原文链接http://www.cnblogs.com/len ...
- 读EXCEL
import xlrdbook=xlrd.open_workbook('app_student.xls')sheet=book.sheet_by_index(0)#根据(索引)顺序获取到sheet页# ...
- [译] 回调地狱——JavaScript异步编程指南
原文:Callback Hell 什么是 “回调地狱”? 在 JavaScript 中,我们经常通过回调来实现异步逻辑,一旦嵌套层级多了,代码结构就容易变得很不直观,最后看起来像这样: fs.read ...
- Android提供支持不同屏幕大小的各种方法
1 http://blog.csdn.net/guolin_blog/article/details/8830286 (手机平板,通过large-layout来区分两条布局文件) 2 http:// ...