1. 程式人生 > >基於flask開發web微信

基於flask開發web微信

window 自己 網頁 time dal -s 最近聯系人 bin in use

流程

階段一

目標:基於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?
ticket=A9QalHCk6CY9iVdnpY9WP9os@qrticket_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/webwxnewloginpage?ticket=A7sp5sbIPRvwPK4QEwKkm6cp@qrticket_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/webwxnewloginpage?ticket=A7sp5sbIPRvwPK4QEwKkm6cp@qrticket_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微信