基于flask开发web微信

Posted jassin-du

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了基于flask开发web微信相关的知识,希望对你有一定的参考价值。

 流程

阶段一

目标:基于falsk编写登录页面,获取二维码

解析:1:、二维码图片地址有个后缀字符串

技术分享图片

 2、图片生成之前,先获取到随机字符串再生成二维码 

技术分享图片

 3、二维码的图片的来源

技术分享图片

4、时间戳

技术分享图片

技术分享图片
from flask import Flask,request,render_template
import time  # 获取时间戳
import requests
import re
app = Flask(__name__)

# app.run(debug=True)   or
app.debug = True

@app.route(/login,methods=[GET,POST])
def login():
    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)
        print(ret.text)
        # 正则 匹配出来uuid
        qcode = re.findall(uuid = "(.*)";,ret.text)[0]
        print(qcode)
        return render_template(login.html,qcode=qcode)
    else:
        pass



if __name__ == __main__:
    app.run()
manage.py
技术分享图片
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>登录页面</title>
</head>
<body>
<div style="width: 200px;margin: 0 auto">
    <h1 style="text-align: center">微信登录</h1>
    <img style="height: 200px;width: 200px" src="https://login.weixin.qq.com/qrcode/{{qcode}}" alt="">
</div>

</body>
</html>
login

技术分享图片

效果

技术分享图片

阶段二

目标:获取头像

长轮询

长轮询:客户端向服务器发送Ajax请求,服务器接到请求后hold住连接,直到有新消息才返回响应信息并关闭连接,
    客户端处理完响应信息后再向服务器发送新的请求。 优点:在无消息的情况下不会频繁的请求,耗费资源小。 缺点:服务器hold连接会消耗资源,返回数据顺序无保证,难于管理维护。 实例:WebQQ、Hi网页版、Facebook IM。

1、长轮询

技术分享图片

2:检测用户是否扫码,未扫码的状态码为408

技术分享图片

技术分享图片

3:扫码成功,并获取用户头像

技术分享图片

 利用ajax写长轮询

    <!--制作长轮询-->
    <script src="/static/jquery-3.2.1.min.js"></script>
    <script>
        $(function () {
            checkLogin();
        });
        
        function checkLogin() {
           $.ajax({
               url:‘/check_login‘,
               type:‘GET‘,
               dataType:‘JSON‘,  //  指定数据类型
               success:function (arg) {
                   // 扫码
                   $(‘#img‘).attr(‘src‘,arg.src);
                   checkLogin()
               }
           }) 
        }
    </script>
技术分享图片
@app.route(‘/check_login‘)
def check_login():
    import time
    time.sleep(10)
    return ‘asassassas‘
manage

技术分享图片

技术分享图片
@app.route(/check_login)
def check_login():
    ‘‘‘
    未扫码的状态码为408,及其连接
    https://login.wx.qq.com/cgi-bin/mmwebwx-bin/login?loginicon=true&uuid=YdXFD_pPqg==&tip=0&r=-1052203142&_=1525764993167
    需要uuid及其时间戳
    :return:
    ‘‘‘
    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=-1052203142&_={1}.format(qcode,ctime)
    #  发送get请求检测是否扫码
    ret = requests.get(check_url)
    print(ret.text)   # 不扫码则返回408 window.code=408;
    if "code=201" in ret.text:
        # 扫码成功 生成用户头像
        src = re.findall("userAvatar = ‘(.*)‘;",ret.text)[0]
        # print(src)   # 获取到用户的头像地址
        response[code] = 201
        response[src] = src
   
    return jsonify(response)
if __name__ == __main__:
    app.run()
manage
技术分享图片
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>登录页面</title>
</head>
<body>
    <div style="width: 200px;margin: 0 auto">
        <h1 style="text-align: center">微信登录</h1>
        <img id="img" style="height: 200px;width: 200px" src="https://login.weixin.qq.com/qrcode/{{qcode}}" >
    </div>

    <!--制作长轮询-->
    <script src="/static/jquery-3.2.1.min.js"></script>
    <script>
        $(function () {
            checkLogin();
        });
        
        function checkLogin() {
           $.ajax({
               url:‘/check_login‘,
               type:‘GET‘,
               dataType:‘JSON‘,  //  指定数据类型
               success:function (arg) {
                   if(arg.code === 201){
                        // 扫码
                        $(‘#img‘).attr(‘src‘,arg.src);
                   }else if(arg.code === 200){
                       // 重定向到用户信息列表
                       location.href = ‘/index‘
                   }else {
                       checkLogin();
                   }
               }
           }) 
        }
    </script>

</body>
</html>
login

阶段三:

确认登录

1、获取凭证信息

技术分享图片

接着会往这个地址发送请求,获取凭证(xml格式)

注意

确认登录的地址

https://wx2.qq.com/cgi-bin/mmwebwx-bin/webwxnewloginpage?ticket=A9QalHCk6CY9iVdnpY9WP9os
@qrticket_0&uuid=QcVoiPFXYw==&lang=zh_CN&scan=1525771690

获取凭证地址

https://wx2.qq.com/cgi-bin/mmwebwx-bin/webwxnewloginpage?
[email protected]_0&uuid=QcVoiPFXYw==&lang=zh_CN&scan=1525771690
&fun=new&version=v2&lang=zh_CN

 

技术分享图片

技术分享图片

初始化

当发的数据是json格式就用payload

技术分享图片

为字典格式  发送过去的数据
BaseRequest: {Uin:
"736490221", Sid: "5S/x/NshjYS7Oq1T", Skey:"@crypt_34187f1b_b2d9f745b8ea17106a3aed8f64b6bd36",…} DeviceID:"e132063792738476" Sid:"5S/x/NshjYS7Oq1T" Skey:"@crypt_34187f1b_b2d9f745b8ea17106a3aed8f64b6bd36" Uin:"736490221"
上面是需要凭证的一些内容
凭证的数据
<error> <ret>0</ret> <message></message>
<skey>@crypt_34187f1b_94ee8455819fb0b67ee356a1d34f6d7c</skey>
<wxsid>oWrr1oPRVKLNs4SI</wxsid> <wxuin>736490221</wxuin>
<pass_ticket>svwwPifX3lEpWr36wXSEc4ufYTQZ9r5i6UmJvTXxfz168gMQtXuSskG%2FCb5%2B3tfy</pass_ticket> <isgrayscale>1</isgrayscale> </error>
最终取值方式   
ticket_dict = session.get(‘ticket_dict‘)
init_url = ‘https://wx2.qq.com/cgi-bin/mmwebwx-bin/webwxinit?r=-1058298025&lang=zh_CN&pass_ticket={0}‘.format(ticket_dict.get("pass_ticket"))
data_dict = {
"BaseRequest":{
"DeviceID":"e132063792738476",
"Sid":ticket_dict.get("wxsid"),
"Skey":ticket_dict.get("Skey"),
"Uin":ticket_dict.get("wxuin")
}
}
技术分享图片
@app.route(/check_login)
def check_login():
    ‘‘‘
    未扫码的状态码为408,及其连接
    https://login.wx.qq.com/cgi-bin/mmwebwx-bin/login?loginicon=true&uuid=YdXFD_pPqg==&tip=0&r=-1052203142&_=1525764993167
    需要uuid及其时间戳
    :return:
    ‘‘‘
    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=-1052203142&_={1}.format(qcode,ctime)
    #  发送get请求检测是否扫码
    ret = requests.get(check_url)
    # print(ret.text)   # 不扫码则返回408 window.code=408;
    if "code=201" in ret.text:
        # 扫码成功 生成用户头像
        src = re.findall("userAvatar = ‘(.*)‘;",ret.text)[0]
        # print(src)   # 获取到用户的头像地址
        response[code] = 201
        response[src] = src
    elif code=200 in ret.text:
        # 确认登录
        ‘‘‘
        window.redirect_uri="https://wx2.qq.com/cgi-bin/mmwebwx-bin/[email protected]_0&uuid=4bMd7uwPpg==&lang=zh_CN&scan=1525769290";
        ‘‘‘
        # 获取凭证的地址
        redirect_url = re.findall(redirect_uri="(.*)";,ret.text)[0]
        # 到取凭证的地址得到凭证
        redirect_uri = redirect_url + "&fun=new&version=v2"
        ticket_ret = requests.get(redirect_uri)
        print(ticket_ret.text)
        # 解析  字典
        ticket_dict = xml_parser(ticket_ret.text)
        # 下面初始化需用到凭证
        session[ticket_dict] = ticket_dict
        response[code] = 200
    return jsonify(response)
确认登录

关于解析xml数据

技术分享图片

方式一:children

技术分享图片
from bs4 import BeautifulSoup

text ="""<error><ret>0</ret>
<message></message><skey>@crypt_2ccf8ab9_70b4bfadb5aeb520357d4ecf46c23713</skey><wxsid>xryEESU5QgXX61ji</wxsid><wxuin>981579400</wxuin><pass_ticket>3nIORdKsOyenOh1%2FoH4U17Qhw8YBkGHJl%2BfqVvaoGoDnmBoQxEJdA%2BZyuHixW1Ow</pass_ticket><isgrayscale>1</isgrayscale></error>"""

soup = BeautifulSoup(text,‘html.parser‘)
div = soup.find(name=‘error‘)
for i  in div.children:
    print(i)
children

方式二:find_all,参数recursive,=True(递归,往子子孙孙里面找) =false(只找儿子)

技术分享图片
from bs4 import BeautifulSoup

def xml_parser(text):
    dic = {}
    soup = BeautifulSoup(text,‘html.parser‘)
    div = soup.find(name=‘error‘)
    for item in div.find_all(recursive=False):
        dic[item.name] = item.text
    return dic

text ="""<error><ret>0</ret>
<message></message><skey>@crypt_2ccf8ab9_70b4bfadb5aeb520357d4ecf46c23713</skey><wxsid>xryEESU5QgXX61ji</wxsid><wxuin>981579400</wxuin><pass_ticket>3nIORdKsOyenOh1%2FoH4U17Qhw8YBkGHJl%2BfqVvaoGoDnmBoQxEJdA%2BZyuHixW1Ow</pass_ticket><isgrayscale>1</isgrayscale></error>"""

dic = xml_parser(text)
print(dic)
find_all

阶段四:

目标:用户初始化,发送POST请求:、

技术分享图片
from flask import Flask,request,render_template,session,jsonify
import time  # 获取时间戳
import requests
import re
from bs4 import BeautifulSoup

app = Flask(__name__)

# app.run(debug=True)   or
app.debug = True
app.secret_key = ‘safsfsfs‘    #  生成密钥, 头像


# 解析xml文件
def xml_parser(text):
    dic = {}
    soup = BeautifulSoup(text,‘html.parser‘)
    div = soup.find(name=‘error‘)
    for item in div.find_all(recursive=False):
        dic[item.name] = item.text
    return dic


@app.route(‘/login‘,methods=[‘GET‘,‘POST‘])
def login():
    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)
        print(ret.text)
        # 正则 匹配出来uuid
        qcode = re.findall(‘uuid = "(.*)";‘,ret.text)[0]
        # 将uuid放到session里面以便下面调用
        session[‘qcode‘] = qcode
        print(qcode)
        return render_template(‘login.html‘,qcode=qcode)
    else:
        pass

@app.route(‘/check_login‘)
def check_login():
    ‘‘‘
    未扫码的状态码为408,及其连接
    https://login.wx.qq.com/cgi-bin/mmwebwx-bin/login?loginicon=true&uuid=YdXFD_pPqg==&tip=0&r=-1052203142&_=1525764993167
    需要uuid及其时间戳
    :return:
    ‘‘‘
    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=-1052203142&_={1}‘.format(qcode,ctime)
    #  发送get请求检测是否扫码
    ret = requests.get(check_url)
    # print(ret.text)   # 不扫码则返回408 window.code=408;
    if "code=201" in ret.text:
        # 扫码成功 生成用户头像
        src = re.findall("userAvatar = ‘(.*)‘;",ret.text)[0]
        # print(src)   # 获取到用户的头像地址
        response[‘code‘] = 201
        response[‘src‘] = src
    elif ‘code=200‘ in ret.text:
        # 确认登录
        ‘‘‘
        window.redirect_uri="https://wx2.qq.com/cgi-bin/mmwebwx-bin/[email protected]_0&uuid=4bMd7uwPpg==&lang=zh_CN&scan=1525769290";
        ‘‘‘
        # 获取凭证的地址
        redirect_url = re.findall(‘redirect_uri="(.*)";‘,ret.text)[0]
        # 到取凭证的地址得到凭证
        redirect_uri = redirect_url + "&fun=new&version=v2"
        ticket_ret = requests.get(redirect_uri)
        print(ticket_ret.text)
        # 解析  字典
        ticket_dict = xml_parser(ticket_ret.text)
        # 下面初始化需用到凭证
        session[‘ticket_dict‘] = ticket_dict
        response[‘code‘] = 200
    return jsonify(response)

@app.route(‘/index‘)
def index():
    ‘‘‘
    用户初始化:
        https://wx2.qq.com/cgi-bin/mmwebwx-bin/webwxinit?r=-1058298025&lang=zh_CN&pass_ticket=9179zbgvzg%252BstA95JF5QmlL1mQ%252BLKqunCOs56ac%252FejGXMC9WrgwRoUi4N7xkdDNL
    ‘‘‘
    ticket_dict = session.get(‘ticket_dict‘)
    init_url = ‘https://wx2.qq.com/cgi-bin/mmwebwx-bin/webwxinit?r=-1058298025&lang=zh_CN&pass_ticket={0}‘.format(ticket_dict.get("pass_ticket"))
    data_dict = {
        "BaseRequest":{
            "DeviceID":"e132063792738476",
            "Sid":ticket_dict.get("wxsid"),
            "Skey":ticket_dict.get("Skey"),
            "Uin":ticket_dict.get("wxuin")
        }
    }
    r1 = requests.post(
        url=init_url,
        json=data_dict
    )
    # 编码
    r1.encoding = ‘utf-8‘
    user_dict = r1.json()
    print(user_dict)


    return render_template(‘/index.html‘,user_dict=user_dict)
if __name__ == ‘__main__‘:
    app.run()
初始化
技术分享图片
<!DOCTYPE html>
<html lang="zh-cn">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Title</title>
</head>
<body>
    <h1>欢迎登录:{{user_dict.User.NickName}}</h1>
    <h3>最近联系人</h3>
    <ul>
        {% for user in user_dict.ContactList%}
        <li>{{user.NickName}}</li>
        {% endfor %}

</body>
</html>
index

技术分享图片

技术分享图片

 注意

这里发送过去的是json类型

    r1 = requests.post(
        url=init_url,
        # 方式一:默认将json的请求发过去
        json=data_dict
        # 方式二:自己写json数据  需要将请求头写上
        # data = json.dumps(data_dict)
        # headers={
        #     ‘Content-Type‘:‘application/json‘
        # }
    )

 




















以上是关于基于flask开发web微信的主要内容,如果未能解决你的问题,请参考以下文章

基于flask开发web微信

学习参考《Flask Web开发:基于Python的Web应用开发实战(第2版)》中文PDF+源代码

[分享]《Flask Web开发:基于Python的Web应用开发实战(第2版)》中文PDF+源代码

《Flask Web开发 基于Python的Web应用开发实战(第2版)》中文PDF+源代码

基于Flask 实现Web微信登陆

Flask之旅《Flask Web开发:基于Python的Web应用开发实战》学习笔记