python---web微信開發


一:輪詢,長輪詢,WebSocket了解

輪詢:

在前端,設置時間內,一直向后端發送請求。
例如:使用setInterval方法設置定時器,一秒向后端發送一次請求,去主動獲取數據,進行更新
由於前端一直請求,后端壓力太大。而且當沒有數據更新,前端一直去請求,太浪費了,沒必要。
代碼簡單

長輪詢:

在輪詢的基礎上,加以改造。Http請求到來,若是不主動close或者return,則連接會一直存在。但是不要讓這個時間太長,會占用太多資源
例如:當前端發送請求,后端拿到后,不去關閉,而是等待一段時間,在這段時間內若是有數據到達,立刻返回,否則直到等待時間結束。
然后返回給前端,前端馬上又發起一次請求......
消息是實時獲取。

WebSocket:

http是單向請求,客戶端去服務端獲取數據。服務端不能主動推送消息。
而websocket類似於socket,可以實現雙向發送,
實現當數據更新,可以主動推送

二:web微信流程介紹

 三:微信登錄開發

from django.shortcuts import render,HttpResponse
from bs4 import BeautifulSoup
import requests
import time,re,json

CTIME = None  #用於保存全局時間戳
QCODE = None  #當我們訪問二維碼時,會產生一個UUID,我們將其存放為全局
TIP = 1  #url中的一個參數tip,當其為1:代表我們還沒有掃描二維碼,當其為0:掃描了二維碼

登錄視圖login,用於顯示二維碼

def login(request):
    global CTIME
    global QCODE
    CTIME = int(time.time())

    data = {
        'appid':'wx782c26e4c19acffb',
        'fun':'new',
        'lang':'zh_CN',
        '_':CTIME
    }

    response = requests.get(
        url="https://login.wx.qq.com/jslogin",
        params=data
    )

    pat_res = re.findall('uuid = "(.*)";',response.text)  #正則匹配UUID
    QCODE = pat_res[0]

    return render(request,"login.html",{'qcode':QCODE})

check_login用於檢測登錄狀態:408未掃描,201掃描二維碼但是未登錄,200點擊登錄

def check_login(request):
    global TIP
    ret = {'code':408,'data':None}
    data = {
        'loginicon':"true",
        'uuid':QCODE,
        'tip':TIP,
        'r':'-577317906',
        '_':int(time.time())
    }
    r1 = requests.get(
        url='https://login.wx.qq.com/cgi-bin/mmwebwx-bin/login',
        params=data
    )

    if 'window.code=408' in r1.text:
        print("無人掃描")
        return HttpResponse(json.dumps(ret))
    elif 'window.code=201' in r1.text:
        ret['code'] = 201
        pat_ret = re.findall("window.userAvatar = '(.*)';",r1.text)[0]
        ret['data'] = pat_ret
        TIP = 0
        return HttpResponse(json.dumps(ret))
    elif 'window.code=200;' in r1.text:
        ret['code'] = 200
        redirect_url = re.findall('window.redirect_uri="(.*)";',r1.text)[0]
        reponse = requests.get(
            url=redirect_url+"&fun=new&version=v2" #url不夠完整,需要我們完善
        )
        # print(reponse.text) #<error><ret>0</ret><message></message><skey>@crypt_7358fe11_af06754907ad9c216768337d80cf0ce7</skey><wxsid>icUySQoySDi2OZFK</wxsid><wxuin>2821071261</wxuin><pass_ticket>IWScm1SE%2BGQ%2BNEaghUBCxbF3xPJSzqXUGTO6BYh3TBEGlw8Wa7qETkA9EEAUudYU</pass_ticket><isgrayscale>1</isgrayscale></error>
        soup = BeautifulSoup(reponse.text,"lxml")
        info_dict = {}
        for tag in soup.find("error").children:
            info_dict[tag.name]=tag.get_text()


        get_user_info_url = 'https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxinit?r=-613135321&pass_ticket='+info_dict['pass_ticket']
        get_user_info_form = {
            'BaseRequest':
            {
                'DeviceID':"e055319847811019",
                'Sid':info_dict['wxsid'],
                'Skey':info_dict['skey'],
                'Uin':info_dict['wxuin']
            }
        }


        reponse2 = requests.post(   #獲取的是用戶信息,最近聯系人,公眾號,自己信息
            url=get_user_info_url,
            json=get_user_info_form,    #注意這里使用的是json,post不允許傳送字典
        )

        reponse2.encoding = "utf-8"
        print(reponse2.text)

        return HttpResponse("OK")
        '''
        新請求 GET 獲取跳轉地址redirect_uri
        https://login.wx.qq.com/cgi-bin/mmwebwx-bin/login?
        loginicon=true
        &uuid=QfsKELYXow==
        &tip=0
        &r=-613406501
        &_=1529621492415
        ---------------------------------------------------------
            window.code=200;
            window.redirect_uri="
                https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxnewloginpage?
                    ticket=ASWg1dxC1oWVbJtZH8V-HhlB@qrticket_0
                    &uuid=QfsKELYXow==
                    &lang=zh_CN
                    &scan=1529621533";
                    
        新請求   GET    獲取憑證pass_ticket    服務端開始設置了cookie,說明在后面的請求中需要攜帶cookie
        https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxnewloginpage?
        ticket=ASWg1dxC1oWVbJtZH8V-HhlB@qrticket_0
        &uuid=QfsKELYXow==
        &lang=zh_CN
        &scan=1529621533
        &fun=new
        &version=v2
        -----------------------------------------------------------------
            <error>
                <ret>0</ret>
                <message></message>
                <skey>@crypt_7358fe11_ea821d506c39f7d75a3e83b4233caab4</skey>
                <wxsid>qUJZlkBIWQ0130QI</wxsid>
                <wxuin>2821071261</wxuin>
                <pass_ticket>xNiKeCBgFkMBfEK8oOK3Gp9qj%2F1HfLpcfPrDwGv3A4nltKskVqoxkECrVYEN9eJJ</pass_ticket>
                <isgrayscale>1</isgrayscale>
            </error>
        
        新請求:獲取用戶所有信息,最近聯系人和公眾號    POST    需要攜帶數據,數據來自於上面憑證中
        https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxinit?
        r=-613135321
        &pass_ticket=xNiKeCBgFkMBfEK8oOK3Gp9qj%252F1HfLpcfPrDwGv3A4nltKskVqoxkECrVYEN9eJJ
        
        數據
        {
            BaseRequest:
            {
                DeviceID:"e055319847811019"
                Sid:"pY7nfHplUAsBOINz"
                Skey:"@crypt_7358fe11_e0ae163bd19650bea336df66837e9f7a"
                Uin:"2821071261"
            }
        }
        --------------------------------------------------------------------
        {
            "BaseResponse": {
            "Ret": 0,
            "ErrMsg": ""
            }
            ,
            "Count": 9,
            "ContactList": [{
            "Uin": 0,
            "UserName": "filehelper",
            "NickName": "文件传输助手",
            "HeadImgUrl": "/cgi-bin/mmwebwx-bin/webwxgeticon?seq=660872310&username=filehelper&skey=@crypt_7358fe11_ea821d506c39f7d75a3e83b4233caab4",
            "ContactFlag": 2,
            "MemberCount": 0,
            "MemberList": [],
            "RemarkName": "",
            "HideInputBarFlag": 0,
            "Sex": 0,
            "Signature": "",
            "VerifyFlag": 0,
            "OwnerUin": 0,
            "PYInitial": "WJCSZS",
            "PYQuanPin": "wenjianchuanshuzhushou",
            "RemarkPYInitial": "",
            "RemarkPYQuanPin": "",
            "StarFriend": 0,
            "AppAccountFlag": 0,
            "Statues": 0,
            "AttrStatus": 0,
            "Province": "",
            "City": "",
            "Alias": "",
            "SnsFlag": 0,
            "UniFriend": 0,
            "DisplayName": "",
            "ChatRoomId": 0,
            "KeyWord": "fil",
            "EncryChatRoomId": "",
            "IsOwner": 0
            },還有其他的]
        }

        新請求
        https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxinit?
        r=-613135321
        &pass_ticket=xNiKeCBgFkMBfEK8oOK3Gp9qj%252F1HfLpcfPrDwGv3A4nltKskVqoxkECrVYEN9eJJ
        
        
        新請求 GET 獲取所有聯系人和公眾號
        https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxgetcontact?
        lang=zh_CN
        &pass_ticket=gWbCT8vTjFeFKXDvfJZ6DtMtHo5d8zzhtLgLoybILn7eeTNSMI4BErA7e9otuPXQ
        &r=1529642330650
        &seq=0
        &skey=@crypt_7358fe11_9dc260b8cffb962a3e475ca50e7813c9
        -----------------------------------------------------------------------------
        {
        "BaseResponse": {
        "Ret": 0,
        "ErrMsg": ""
        }
        ,
        "MemberCount": 162,
        "MemberList": [{
            "Uin": 0,
            "UserName": "@39ef4d4197e9a7388e41fc9de150b3e28bf125082f1e442822814dec4803c6a0",
            "NickName": "宁静致远",
            "HeadImgUrl": "/cgi-bin/mmwebwx-bin/webwxgeticon?seq=0&username=@39ef4d4197e9a7388e41fc9de150b3e28bf125082f1e442822814dec4803c6a0&skey=@crypt_7358fe11_9dc260b8cffb962a3e475ca50e7813c9",
            "ContactFlag": 1,
            "MemberCount": 0,
            "MemberList": [],
            "RemarkName": "",
            "HideInputBarFlag": 0,
            "Sex": 1,
            "Signature": "凶巴巴呛贝贝",
            "VerifyFlag": 0,
            "OwnerUin": 0,
            "PYInitial": "NJZY",
            "PYQuanPin": "ningjingzhiyuan",
            "RemarkPYInitial": "",
            "RemarkPYQuanPin": "",
            "StarFriend": 0,
            "AppAccountFlag": 0,
            "Statues": 0,
            "AttrStatus": 4197,
            "Province": "河南",
            "City": "郑州",
            "Alias": "",
            "SnsFlag": 17,
            "UniFriend": 0,
            "DisplayName": "",
            "ChatRoomId": 0,
            "KeyWord": "",
            "EncryChatRoomId": "",
            "IsOwner": 0
            },
            還有其他
        ]
        '''
各個url詳細請求

前端代碼:顯示二維碼和頭像

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<img id="qrcode" style="width: 340px;height: 340px;" src="https://login.weixin.qq.com/qrcode/{{ qcode }}" alt="">
</body>
</html>
<script src="/static/jquery.js"></script>
<script>
    $(function(){
        checkLogin();
    })

    function checkLogin() {
        $.ajax({
            url:'/check-login.html',
            type:'GET',
            dataType:"json",
            success:function(data){
                console.log(data.code);
                if (data.code==408){
                    checkLogin();
                }
                else if(data.code==201){
                    $("#qrcode").attr('src',data.data)
                    checkLogin();
                }
            }
        })
    }
</script>

測試返回的最近聯系人和公眾號信息

user_dict = {}


for item in user_dict.items():
    print(item)

for item in user_dict['ContactList']:   #最近聯系人
    print(item['PYQuanPin'],item['NickName'])


for item in user_dict['MPSubscribeMsgList']:    #公眾號和推送消息
    print(item['UserName'],item['NickName'])
    for item2 in item['MPArticleList']:
        print(item2['Title'],item2['Cover'],item2['Digest'],item2['Url'])
最近聯系人和公眾號
('ClientVersion', 637929271)
('GrayScale', 1)
('Count', 10)
('SystemTime', 1529661118)
('MPSubscribeMsgList:公眾號列表,含有文章推送等信息', [{'UserName': '@393d71e59f81ac2feca148e8e269c0df', 'MPArticleList': [{'Title': '', 'Digest': '', 'Url': '', 'Cover': '圖片'}, ], 'MPArticleCount': 2, 'Time': 1529651105, 'NickName': '人工智能頭條'},])
('ChatSet', 'filehelper,@@7c7137978e7349eac97453fa2adc290df295eaba3e7981e07ff85111f94a403c,weixin,@0fdf14d27dc0b2d34d013329ec498aae6284dbc340bdfbd8741227a72b1b3fa4,@393d71e59f81ac2feca148e8e269c0df,@@4d7d0c68e8445a6d69a5e3a2415c57c8f46858724cfdef8618b5790094e5de37,@@6b45638d8a8394a5bea103bd55ef49ce69dad73b8eda94dd5f63a126ec0e6ee4,@@d6c45082c0686e0cef729f3cb20db704b381b2aef67fe0a8a82151869220c8ef,@@03e7d8c59c30bb81dc0f2dc683b8e7a6f4a707f2aac6655c6e5036c349a96fe3,@02bf3be3c826bc38d4461d3ee52704e8,')
('MPSubscribeMsgCount:最近推送的公眾號數目', 2)
('BaseResponse', {'ErrMsg': '', 'Ret': 0})
('SKey', '@crypt_7358fe11_08012eadffc70f5c3189f802236830be')
('ClickReportInterval', 600000)
('InviteStartCount', 40)
('User:用戶自己的信息', {'VerifyFlag': 0, 'HeadImgFlag': 1, 'Uin': 2821071261, 'NickName': '寧靜致遠', 'AppAccountFlag': 0, 'UserName': '@c959c389ab390d9f71d3f528f5a4ee1e81d6c8cd4aaf48d8b1f0077073660c5c', 'HeadImgUrl': '/cgi-bin/mmwebwx-bin/webwxgeticon?seq=1753775271&username=@c959c389ab390d9f71d3f528f5a4ee1e81d6c8cd4aaf48d8b1f0077073660c5c&skey=@crypt_7358fe11_08012eadffc70f5c3189f802236830be', 'ContactFlag': 0, 'RemarkPYInitial': '', 'SnsFlag': 17, 'PYQuanPin': '', 'WebWxPluginSwitch': 0, 'HideInputBarFlag': 0, 'RemarkPYQuanPin': '', 'Signature': '凶巴巴嗆貝貝', 'Sex': 1, 'StarFriend': 0, 'PYInitial': '', 'RemarkName': ''})
('ContactList:最近聯系人信息', [
 {'VerifyFlag': 0, 'Uin': 0, 'Signature': '', 'AppAccountFlag': 0, 'HeadImgUrl': '/cgi-bin/mmwebwx-bin/webwxgeticon?seq=660872310&username=filehelper&skey=@crypt_7358fe11_08012eadffc70f5c3189f802236830be', 'PYInitial': 'WJCSZS', 'Province': '', 'PYQuanPin': 'wenjianchuanshuzhushou', 'DisplayName': '', 'RemarkName': '', 'IsOwner': 0, 'Sex': 0, 'EncryChatRoomId': '', 'KeyWord': 'fil', 'City': '', 'ChatRoomId': 0, 'RemarkPYQuanPin': '', 'Alias': '', 'UniFriend': 0, 'UserName': 'filehelper', 'MemberCount': 0, 'ContactFlag': 2, 'RemarkPYInitial': '', 'Statues': 0, 'AttrStatus': 0, 'SnsFlag': 0, 'HideInputBarFlag': 0, 'NickName': '文件傳輸助手', 'OwnerUin': 0, 'StarFriend': 0, 'MemberList': []},])
('SyncKey', {'List': [{'Key': 1, 'Val': 677540039}, {'Key': 2, 'Val': 677540219}, {'Key': 3, 'Val': 677540036}, {'Key': 1000, 'Val': 1529658962}], 'Count': 4})
相關數據打印(格式)

 四:顯示最近聯系人和公眾號

視圖所有代碼:對於上面是有所修改的

from django.shortcuts import render,HttpResponse,redirect
from bs4 import BeautifulSoup
import requests
import time,re,json

CTIME = None
QCODE = None
TIP = 1
TICKET_DICT = {}    #保存憑證信息
ALL_COOKIE_DICT = {}


# Create your views here.
def login(request):
    global CTIME
    global QCODE
    CTIME = int(time.time()*1000)

    data = {
        'appid':'wx782c26e4c19acffb',
        'fun':'new',
        'lang':'zh_CN',
        '_':CTIME
    }

    response = requests.get(
        url="https://login.wx.qq.com/jslogin",
        params=data
    )

    pat_res = re.findall('uuid = "(.*)";',response.text)
    QCODE = pat_res[0]

    return render(request,"login.html",{'qcode':QCODE})

def check_login(request):
    global TIP
    ret = {'code':408,'data':None}
    data = {
        'loginicon':"true",
        'uuid':QCODE,
        'tip':TIP,
        'r':'-577317906',
        '_':int(time.time())
    }
    r1 = requests.get(
        url='https://login.wx.qq.com/cgi-bin/mmwebwx-bin/login',
        params=data
    )

    if 'window.code=408' in r1.text:
        print("無人掃描")
        return HttpResponse(json.dumps(ret))
    elif 'window.code=201' in r1.text:
        ret['code'] = 201
        pat_ret = re.findall("window.userAvatar = '(.*)';",r1.text)[0]
        ret['data'] = pat_ret
        TIP = 0
        return HttpResponse(json.dumps(ret))
    elif 'window.code=200;' in r1.text:
        ret['code'] = 200
        redirect_url = re.findall('window.redirect_uri="(.*)";', r1.text)[0]
        reponse = requests.get(     #獲取憑證,這里也開始設置cookie了,所以我們在這里向后需要記錄cookie
            url=redirect_url + "&fun=new&version=v2"  # url不夠完整,需要我們完善
        )
        ALL_COOKIE_DICT.update(reponse.cookies)

        soup = BeautifulSoup(reponse.text, "lxml")
        info_dict = {}
        for tag in soup.find("error").children:
            info_dict[tag.name] = tag.get_text()

        global TICKET_DICT
        TICKET_DICT.update(info_dict)

        ret['code']=200

        return HttpResponse(json.dumps(ret))


def user(request):
    get_user_info_url = 'https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxinit?r=-613135321&pass_ticket=' + TICKET_DICT[
        'pass_ticket']
    get_user_info_form = {
        'BaseRequest':
            {
                'DeviceID': "e055319847811019",
                'Sid': TICKET_DICT['wxsid'],
                'Skey': TICKET_DICT['skey'],
                'Uin': TICKET_DICT['wxuin']
            }
    }

    reponse2 = requests.post(  # 獲取的是用戶信息,幾個聯系人,公眾號,自己信息
        url=get_user_info_url,
        json=get_user_info_form,  # 注意這里使用的是json,post不允許傳送字典
    )
    ALL_COOKIE_DICT.update(reponse2.cookies)

    reponse2.encoding = "utf-8"

    user_info_dict = json.loads(reponse2.text)  # 獲取的是用戶信息,幾個聯系人,公眾號,自己信息

    return render(request, "user.html", {'user_info_dict': user_info_dict})
views修改后的代碼,主要是將憑證放入全局字典

視圖方法user去獲取最近聯系人

注意:我們將上面的憑證保存到了全局變量中TICKET_DICT方便查詢使用

def user(request): get_user_info_url
= 'https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxinit?r=-613135321&pass_ticket=' + TICKET_DICT[ 'pass_ticket'] get_user_info_form = { 'BaseRequest': { 'DeviceID': "e055319847811019", 'Sid': TICKET_DICT['wxsid'], 'Skey': TICKET_DICT['skey'], 'Uin': TICKET_DICT['wxuin'] } } reponse2 = requests.post( # 獲取的是用戶信息,幾個聯系人,公眾號,自己信息 url=get_user_info_url, json=get_user_info_form, # 注意這里使用的是json,post不允許傳送字典 ) ALL_COOKIE_DICT.update(reponse2.cookies) reponse2.encoding = "utf-8" user_info_dict = json.loads(reponse2.text) # 獲取的是用戶信息,幾個聯系人,公眾號,自己信息 return render(request, "user.html", {'user_info_dict': user_info_dict})

前端代碼

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <div>
        <h3>最近聯系人</h3>
        <ul>
            {% for item in user_info_dict.ContactList %}
                <li>{{ item.NickName }}</li>
            {% endfor %}
        </ul>
        <a href="/contact-list.html">獲取更多聯系人</a>
    </div>
    <div>
        <h3>微信公眾號</h3>
        <div>
            {% for item in user_info_dict.MPSubscribeMsgList %}
                <h4>{{ item.NickName }}</h4>
                <ul>
                    {% for item2 in item.MPArticleList %}
                        <li>
                            <a href="{{ item2.Url }}">
                                {{ item2.Title }}
                            </a>
                        </li>
                    {% endfor %}
                </ul>
            {% endfor %}
        </div>
    </div>
</body>
</html>

五:顯示所有聯系人

視圖所有的修改:主要在設置一個全局字典存放網站cookie,注意這里是需要攜帶cookie的,而cookie是在我們點擊登錄后,服務器開始設置的,我們需要去獲取自那時以后的所有cookie

from django.shortcuts import render,HttpResponse,redirect
from bs4 import BeautifulSoup
import requests
import time,re,json

CTIME = None
QCODE = None
TIP = 1
TICKET_DICT = {}    #保存憑證信息
ALL_COOKIE_DICT = {}


# Create your views here.
def login(request):
    global CTIME
    global QCODE
    CTIME = int(time.time()*1000)

    data = {
        'appid':'wx782c26e4c19acffb',
        'fun':'new',
        'lang':'zh_CN',
        '_':CTIME
    }

    response = requests.get(
        url="https://login.wx.qq.com/jslogin",
        params=data
    )

    pat_res = re.findall('uuid = "(.*)";',response.text)
    QCODE = pat_res[0]

    return render(request,"login.html",{'qcode':QCODE})

def check_login(request):
    global TIP
    ret = {'code':408,'data':None}
    data = {
        'loginicon':"true",
        'uuid':QCODE,
        'tip':TIP,
        'r':'-577317906',
        '_':int(time.time())
    }
    r1 = requests.get(
        url='https://login.wx.qq.com/cgi-bin/mmwebwx-bin/login',
        params=data
    )

    if 'window.code=408' in r1.text:
        print("無人掃描")
        return HttpResponse(json.dumps(ret))
    elif 'window.code=201' in r1.text:
        ret['code'] = 201
        pat_ret = re.findall("window.userAvatar = '(.*)';",r1.text)[0]
        ret['data'] = pat_ret
        TIP = 0
        return HttpResponse(json.dumps(ret))
    elif 'window.code=200;' in r1.text:
        ret['code'] = 200
        redirect_url = re.findall('window.redirect_uri="(.*)";', r1.text)[0]
        reponse = requests.get(     #獲取憑證,這里也開始設置cookie了,所以我們在這里向后需要記錄cookie
            url=redirect_url + "&fun=new&version=v2"  # url不夠完整,需要我們完善
        )
        ALL_COOKIE_DICT.update(reponse.cookies)

        soup = BeautifulSoup(reponse.text, "lxml")
        info_dict = {}
        for tag in soup.find("error").children:
            info_dict[tag.name] = tag.get_text()

        global TICKET_DICT
        TICKET_DICT.update(info_dict)

        ret['code']=200

        return HttpResponse(json.dumps(ret))


def user(request):
    get_user_info_url = 'https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxinit?r=-613135321&pass_ticket=' + TICKET_DICT[
        'pass_ticket']
    get_user_info_form = {
        'BaseRequest':
            {
                'DeviceID': "e055319847811019",
                'Sid': TICKET_DICT['wxsid'],
                'Skey': TICKET_DICT['skey'],
                'Uin': TICKET_DICT['wxuin']
            }
    }

    reponse2 = requests.post(  # 獲取的是用戶信息,幾個聯系人,公眾號,自己信息
        url=get_user_info_url,
        json=get_user_info_form,  # 注意這里使用的是json,post不允許傳送字典
    )
    ALL_COOKIE_DICT.update(reponse2.cookies)

    reponse2.encoding = "utf-8"

    user_info_dict = json.loads(reponse2.text)  # 獲取的是用戶信息,幾個聯系人,公眾號,自己信息

    return render(request, "user.html", {'user_info_dict': user_info_dict})


def contact_list(request):
    get_all_user_url = 'https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxgetcontact?lang=zh_CN&pass_ticket=%s&r=%s&seq=0&skey=%s' % (TICKET_DICT['pass_ticket'],int(time.time()*1000),TICKET_DICT['skey'])

    reponse = requests.get(
        url=get_all_user_url,   #這里需要用到cookie
        cookies=ALL_COOKIE_DICT
    )

    reponse.encoding = "utf-8"
    contact_info_list = json.loads(reponse.text)


    return render(request,"contact_info.html",{'contact_info_list':contact_info_list})
所有視圖代碼,主要修改在ALL_COOKIE_DICT 存放cookie

不攜帶cookie情況:

視圖方法:contact_list

def contact_list(request):
    get_all_user_url = 'https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxgetcontact?lang=zh_CN&pass_ticket=%s&r=%s&seq=0&skey=%s' % (TICKET_DICT['pass_ticket'],int(time.time()*1000),TICKET_DICT['skey'])

    reponse = requests.get(
        url=get_all_user_url,   #這里需要用到cookie
        cookies=ALL_COOKIE_DICT
    )

    reponse.encoding = "utf-8"
    contact_info_list = json.loads(reponse.text)


    return render(request,"contact_info.html",{'contact_info_list':contact_info_list})

 前端代碼:

 

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <div>
        <h3>全部聯系人列表</h3>
        <ul>
            {% for item in contact_info_list.MemberList %}
            <li>{{ item.NickName }}</li>
            {% endfor %}
        </ul>
    </div>
</body>
</html>

 六:模擬發送信息

發送信息的url:

https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxsendmsg?lang=zh_CN&pass_ticket=l8yQcPtEelgrNY6fSnMf72i%252BoP10LCLTdmjnFgEQOCK9n7401krRfKnc0xMbNweJ

POST傳遞數據內容:

{
"BaseRequest":  #這里數據存放在全局憑證中 {"Uin":2821071261, "Sid":"xU10r+19IxmPU8Fb", "Skey":"@crypt_7358fe11_5fc69b570e562f35f5e96aa1039d83aa", "DeviceID":"e308142734343946" }, "Msg":  #發送的數據信息 {"Type":1,  #文本信息 "Content":"參數",  #發送的數據 "FromUserName":"@c63e475396e438ef81d9825832217c06e4cc302269db05b7eae7e2980de2d56d",  #我的username "ToUserName":"@94bcc0a92c726c0e2639ffa59618549d222bee0107150515cf247dc8d45f8144",  #發給誰username "LocalID":"15296541823070630",  #和時間戳一致 "ClientMsgId":"15296541823070630"  #時間戳 }, "Scene":0 }
{"BaseRequest":
     {"Uin":2821071261,
      "Sid":"xU10r+19IxmPU8Fb",
      "Skey":"@crypt_7358fe11_5fc69b570e562f35f5e96aa1039d83aa",
      "DeviceID":"e149192355196085"  #可變的設備ID
      },
 "Msg":
     {"Type":1,  
      "Content":"哈哈哈",  #發送內容改變了
      "FromUserName":"@c63e475396e438ef81d9825832217c06e4cc302269db05b7eae7e2980de2d56d",
      "ToUserName":"@94bcc0a92c726c0e2639ffa59618549d222bee0107150515cf247dc8d45f8144",
      "LocalID":"15296546798310239",  #同時間戳一致
      "ClientMsgId":"15296546798310239"  #時間戳改變了
      },
"Scene":0
 }

 修改前端contact_info.html頁面

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link href="/static/css/bootstrap.min.css" rel="stylesheet">
    <link href="/static/css/nifty.min.css" rel="stylesheet">
    <link href="/static/css/demo/nifty-demo-icons.min.css" rel="stylesheet">
    <link href="/static/css/demo/nifty-demo.min.css" rel="stylesheet">
    <link href="/static/plugins/pace/pace.min.css" rel="stylesheet">
    <script src="/static/js/jquery-2.2.4.min.js"></script>
    <script>
    $(function(){
        $(".list-group-item").click(function(){
            $(".list-unstyled").empty();
            $(this).siblings().removeClass("active");
            $(this).addClass("active");
            var NickName = $(this).first().text().trim();
            $(".panel-title").text(NickName);
        })
    })
    </script>
    <script src="/static/plugins/pace/pace.min.js"></script>
    <script src="/static/js/bootstrap.min.js"></script>
    <script src="/static/js/nifty.min.js"></script>
    <script src="/static/js/demo/nifty-demo.min.js"></script>
    <script src="/static/plugins/flot-charts/jquery.flot.min.js"></script>
    <script src="/static/plugins/flot-charts/jquery.flot.resize.min.js"></script>
    <script src="/static/plugins/gauge-js/gauge.min.js"></script>
    <script src="/static/plugins/skycons/skycons.min.js"></script>
    <script src="/static/plugins/easy-pie-chart/jquery.easypiechart.min.js"></script>
    <script src="/static/js/demo/widgets.js"></script>
</head>
<body>
<div id="container" class="effect  aside-bright mainnav-sm aside-right aside-in">
    <div class="boxed">
        <div id="content-container">
            <div class="row">
                <div class="col-md-8 col-lg-8 col-sm-8">

            <!--Chat widget-->
            <!--===================================================-->
            <div class="panel" style="height: 640px">
                <!--Heading-->
                <div class="panel-heading">
                    <h3 class="panel-title">Chat</h3>
                </div>

                <!--Widget body-->
                <div style="height:510px;padding-top:0px;" class="widget-body">
                    <div class="nano">
                        <div class="nano-content pad-all">
                            <ul class="list-unstyled media-block">
                                <li class="mar-btm">
                                    <div class="media-left">
                                        <img src="img/profile-photos/1.png" class="img-circle img-sm" alt="Profile Picture">
                                    </div>
                                    <div class="media-body pad-hor">
                                        <div class="speech">
                                            <a href="#" class="media-heading">Aaron Chavez</a>
                                            <p>Hello Lucy, how can I help you today ?</p>
                                            <p class="speech-time">
                                            <i class="demo-pli-clock icon-fw"></i>09:23AM
                                            </p>
                                        </div>
                                    </div>
                                </li>
                                <li class="mar-btm">
                                    <div class="media-right">
                                        <img src="img/profile-photos/8.png" class="img-circle img-sm" alt="Profile Picture">
                                    </div>
                                    <div class="media-body pad-hor speech-right">
                                        <div class="speech">
                                            <a href="#" class="media-heading">Lucy Doe</a>
                                            <p>Hi, I want to buy a new shoes.</p>
                                            <p class="speech-time">
                                                <i class="demo-pli-clock icon-fw"></i> 09:23AM
                                            </p>
                                        </div>
                                    </div>
                                </li>
                            </ul>
                        </div>
                    </div>

                    <!--Widget footer-->
                    <div class="panel-footer" style="height: 90px;">
                        <div class="row">
                            <div class="col-xs-9">
                                <input type="text" placeholder="Enter your text" class="form-control chat-input">
                            </div>
                            <div class="col-xs-3">
                                <button class="btn btn-primary btn-block" onclick="sendMsg(this);" type="submit">Send</button>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
            <!--===================================================-->
            <!--Chat widget-->

        </div>
                <div class="col-md-4 col-lg-4 col-sm-4">
                    <aside id="aside-container">
                <div id="aside">
                    <div class="nano has-scrollbar">
                        <div class="nano-content" tabindex="0" style="right: -17px;">

                            <!--Nav tabs-->
                            <!--================================-->
                            <ul class="nav nav-tabs nav-justified">
                                <li class="active">
                                    <a href="#demo-asd-tab-1" data-toggle="tab">
                                        <i class="demo-pli-speech-bubble-7"></i>
                                    </a>
                                </li>
                            </ul>
                            <!--================================-->
                            <!--End nav tabs-->

                            <!-- Tabs Content -->
                            <!--================================-->
                            <div class="tab-content">
                                <div class="tab-pane fade in active" id="demo-asd-tab-1">
                                    <p class="pad-hor text-semibold text-main">
                                        <span class="pull-right badge badge-success">{{ contact_info_list.MemberCount }}</span> Friends
                                    </p>

                                    <!--Works-->
                                    <div class="list-group bg-trans">
                                        {% for item in contact_info_list.MemberList %}
                                            <a href="#" for="{{ item.UserName }}" class="list-group-item">
                                                <span class="badge badge-purple badge-icon badge-fw pull-left"></span> {{ item.NickName }}
                                            </a>
                                        {% endfor %}
                                    </div>
                                </div>
                            </div>
                        </div>
                    <div class="nano-pane" style="display: none;"><div class="nano-slider" style="height: 4059px; transform: translate(0px, 0px);"></div></div></div>
                </div>
            </aside>
                </div>
            </div>
        </div>
    </div>
</div>
</body>
</html>

<script>
    function sendMsg(ths){
        var sel_tag = $(".list-group").find(".active")
        if(sel_tag.length==0){
            return false;
        }
        var msg = $(ths).parents(".panel-footer").find(".chat-input").val();
        var sendMsg={
            'ToUserName':sel_tag.attr("for"),
            'Type':1,
            'Content':msg,
            'csrfmiddlewaretoken':'{{ csrf_token }}'
        }

        $.ajax({
            url:"send-msg.html",
            data:sendMsg,
            type:"POST",
            dataType:"json",
            success:function(callback){
                if (callback.code==200){
                    var dt = new Date()
                    var now_time = dt.toLocaleString();

                    console.log(callback);
                    var li = '<li class="mar-btm"><div class="media-right"><img src="'+callback.headImgUrl+'" class="img-circle img-sm" alt="Profile Picture"></div>';
                    li += '<div class="media-body pad-hor speech-right"><div class="speech"><a href="#" class="media-heading">'+callback.username+'</a>';
                    li += '<p>'+msg+'</p>';
                    li += '<p class="speech-time">';
                    li += '<i class="demo-pli-clock icon-fw"></i>'+now_time;
                    li += '</p></div></div></li>';
                    $(ths).parents(".widget-body").find(".list-unstyled").append(li);
                    $(ths).parents(".panel-footer").find(".chat-input").val("");
                }
            }
        })
    }
</script>
前端代碼使用ajax向后端傳送

后端代碼send_msg

注意:處理傳送中文時,在requests模塊有點麻煩,下面代碼有寫解決方法

def send_msg(request):
    ret = {
        'code':200,
        'error':'Send Success',
        'data':{}
    }

    recv_data = request.POST

    if not recv_data:
        ret['code']=400
        ret['data']="Send failure"
        return HttpResponse(json.dumps(ret))

    #數據整合
    Send_data={}
    Send_data['BaseRequest'] = {
        'DeviceID': "e055319847811019",
        'Sid': TICKET_DICT['wxsid'],
        'Skey': TICKET_DICT['skey'],
        'Uin': TICKET_DICT['wxuin']
    }

    Send_data['Msg'] = {
        'Type':recv_data.get("Type",1),
        'Content':recv_data.get("Content"),
        'FromUserName':USER_INIT_DICT['User']['UserName'],
        'ToUserName':recv_data.get("ToUserName"),
        'LocalID':int(time.time()*1000),
        'ClientMsgId':int(time.time()*1000),
    }
    Send_data['Scene']=0

    send_url = 'https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxsendmsg?lang=zh_CN&pass_ticket=%s'%TICKET_DICT['pass_ticket']
    # reponse = requests.post(
    #     url=send_url,
    #     json=Send_data, #注意這里如果使用json,會將中文轉換為Unicode
    #     cookies=ALL_COOKIE_DICT
    # )
    reponse = requests.post(
        url=send_url,
        #若是有中文,需要加上ensure_ascii=False,若是字符串中含有中文,request傳遞數據時,將中文轉換為字節,無法為我們轉換。需要我們提前使用encoding編碼,直接傳遞字節,不讓requests為我們轉換
        #data可以是字典,字符串,字節,既然對於字典,字符串直接含有中文不正確,直接轉字節傳送,py3默認是utf-8,所以我們直接傳送字節就可以
        data=bytes(json.dumps(Send_data,ensure_ascii=False),encoding="utf-8"), #注意這里如果使用json,會將中文轉換為Unicode
        cookies=ALL_COOKIE_DICT  #攜帶cookie
    )

    reponse.encoding = "utf-8"

    ret_status = re.findall('"Ret": (.*),', reponse.text)[0]
    ret_error = re.findall('"ErrMsg": "(.*)"', reponse.text)[0]

    if int(ret_status) != 0:
        ret['code']=401
        ret['data']=ret_error
        return HttpResponse(json.dumps(ret))

    ret['username'] = USER_INIT_DICT['User']['NickName']
    ret['headImgUrl'] = 'https://wx.qq.com'+USER_INIT_DICT['User']['HeadImgUrl']

    return HttpResponse(json.dumps(ret))

 七:實現長輪詢接收消息

先參考微信的實例:微信依靠兩個url實現去后端獲取數據

1.webwxsync:ajax使用POST,長輪詢去獲取發送的消息,和獲取一個SyncCheckKey,下面檢測是否有消息到了需要攜帶這個SyncCheckKey

https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxsync?sid=NOWucA2Et3xw0l8a&skey=@crypt_7358fe11_181eea60999ab937ed1ff13e1d1f7853&pass_ticket=9ZK9OoNzaLxkdRqVWghy7uGzWFvsIzXNWDjgeJqTskg3Bl08tQxAZ9t0hcEYOzmO

要傳遞的POST數據
{  
"BaseRequest":{  #都是已經獲取的數據
"Uin":2821071261,
"Sid":"NOWucA2Et3xw0l8a",
"Skey":"@crypt_7358fe11_181eea60999ab937ed1ff13e1d1f7853",
"DeviceID":"e937865997050874"
},
"SyncKey":{  #我們上一次的SyncKey值
"Count":9,"List":[{"Key":1,"Val":677540346},{"Key":2,"Val":677540435},{"Key":3,"Val":677540036},{"Key":11,"Val":677540181},{"Key":201,"Val":1529672373},{"Key":203,"Val":1529658601},{"Key":1000,"Val":1529658962},{"Key":1001,"Val":1529659033},{"Key":2001,"Val":1529480143}]
},
"rr":-664997335  #未知
}
{
"BaseResponse": {
"Ret": 0,
"ErrMsg": ""
}
,
"AddMsgCount": 0,
"AddMsgList": [],
"ModContactCount": 0,
"ModContactList": [],
"DelContactCount": 0,
"DelContactList": [],
"ModChatRoomMemberCount": 0,
"ModChatRoomMemberList": [],
"Profile": {
"BitFlag": 0,
"UserName": {
"Buff": ""
}
,
"NickName": {
"Buff": ""
}
,
"BindUin": 0,
"BindEmail": {
"Buff": ""
}
,
"BindMobile": {
"Buff": ""
}
,
"Status": 0,
"Sex": 0,
"PersonalCard": 0,
"Alias": "",
"HeadImgUpdateFlag": 0,
"HeadImgUrl": "",
"Signature": ""
}
,
"ContinueFlag": 0,
"SyncKey": {
"Count": 9,
"List": [
    {
    "Key": 1,
    "Val": 677540346
    }
    ,{
    "Key": 2,
    "Val": 677540423
    }
    ,{
    "Key": 3,
    "Val": 677540036
    }
    ,{
    "Key": 11,
    "Val": 677540181
    }
    ,{
    "Key": 201,
    "Val": 1529671726
    }
    ,{
    "Key": 203,
    "Val": 1529658601
    }
    ,{
    "Key": 1000,
    "Val": 1529658962
    }
    ,{
    "Key": 1001,
    "Val": 1529659033
    }
    ,{
    "Key": 2001,
    "Val": 1529480143
    }
]
}
,
"SKey": "",
"SyncCheckKey": {
"Count": 9,
"List": [
    {
    "Key": 1,
    "Val": 677540346
    }
    ,{
    "Key": 2,
    "Val": 677540423
    }
    ,{
    "Key": 3,
    "Val": 677540036
    }
    ,{
    "Key": 11,
    "Val": 677540181
    }
    ,{
    "Key": 201,
    "Val": 1529671726
    }
    ,{
    "Key": 203,
    "Val": 1529658601
    }
    ,{
    "Key": 1000,
    "Val": 1529658962
    }
    ,{
    "Key": 1001,
    "Val": 1529659033
    }
    ,{
    "Key": 2001,
    "Val": 1529480143
    }
]
}
}
獲取的數據:SyncKey
2.synccheck:輪詢請求,用於檢測是否有人發消息過來。注意:當我們剛剛登陸時,是有一個初始的synckey的,可以在《相關數據打印(格式)》那里看到

https://webpush.wx.qq.com/cgi-bin/mmwebwx-bin/synccheck?r=1529672369137&skey=%40crypt_7358fe11_181eea60999ab937ed1ff13e1d1f7853&sid=NOWucA2Et3xw0l8a&uin=2821071261&deviceid=e539832593408529&synckey=1_677540346%7C2_677540434%7C3_677540036%7C11_677540181%7C201_1529672366%7C203_1529658601%7C1000_1529658962%7C1001_1529659033%7C2001_1529480143&_=1529671539738
https:
//webpush.wx.qq.com/cgi-bin/mmwebwx-bin/synccheck? r=1529671730362 #時間戳 &skey=%40crypt_7358fe11_181eea60999ab937ed1ff13e1d1f7853&sid=NOWucA2Et3xw0l8a &uin=2821071261 #和其他數據一起放在TICKET_DICT中 &deviceid=e065841963151848 #設備id &synckey= 1_677540346 1 677540346 #和上一個請求url中接收的數據一致 %7C | 2_677540423 2 677540423 %7C | 3_677540036 %7C 11_677540181%7C201_1529671726%7C203_1529658601%7C1000_1529658962%7C1001_1529659033%7C2001_1529480143 &_=1529671539706 #時間戳 r=1529672904066&skey=%40crypt_7358fe11_181eea60999ab937ed1ff13e1d1f7853&sid=NOWucA2Et3xw0l8a&uin=2821071261&deviceid=e647845000558861&synckey=1_677540346%7C2_677540435%7C3_677540036%7C11_677540181%7C201_1529672373%7C203_1529658601%7C1000_1529658962%7C1001_1529659033%7C2001_1529480143&_=1529671539759

返回值
window.synccheck
={retcode:"0",selector:"2"}  #有消息到來
window.synccheck={retcode:"0",selector:"0"}  #沒有消息到來

當有消息到來:我們將從webwxsync中獲取到數據

 

{
"BaseResponse": {
"Ret": 0,
"ErrMsg": ""
}
,
"AddMsgCount": 1,  #到來的消息數目 "AddMsgList": [{
"MsgId": "3138475736544982077",
"FromUserName": "@@e780498496215d2077ef72216ce629bfd570595c2d1b99192aa32fae78a3e489",  #來自誰的微信 "ToUserName": "@9419ce13e311ec0469803ba1667703ca16fd3e9ec13d5998c52f42dba33f4c3d",  #這是我們的微信 "MsgType": 1,
"Content": "@0e722870282c2e079ec9ddc7304ef501bb99d45465501efac52f8b050498d8a4:<br/>@A~筱嵩灬 10分钟吧",    #發過來的信息,我們未編碼 "Status": 3,  #狀態
"ImgStatus": 1,
"CreateTime": 1529673345,
"VoiceLength": 0,
"PlayLength": 0,
"FileName": "",
"FileSize": "",
"MediaId": "",
"Url": "",
"AppMsgType": 0,
"StatusNotifyCode": 0,
"StatusNotifyUserName": "",
"RecommendInfo": {
"UserName": "",
"NickName": "",
"QQNum": 0,
"Province": "",
"City": "",
"Content": "",
"Signature": "",
"Alias": "",
"Scene": 0,
"VerifyFlag": 0,
"AttrStatus": 0,
"Sex": 0,
"Ticket": "",
"OpCode": 0
}
,
"ForwardFlag": 0,
"AppInfo": {
"AppID": "",
"Type": 0
}
,
"HasProductId": 0,
"Ticket": "",
"ImgHeight": 0,
"ImgWidth": 0,
"SubMsgType": 0,
"NewMsgId": 3138475736544982077,
"OriContent": "",
"EncryFileName": ""
}
],
"ModContactCount": 0,
"ModContactList": [],
"DelContactCount": 0,
"DelContactList": [],
"ModChatRoomMemberCount": 0,
"ModChatRoomMemberList": [],
"Profile": {
"BitFlag": 0,
"UserName": {
"Buff": ""
}
,
"NickName": {
"Buff": ""
}
,
"BindUin": 0,
"BindEmail": {
"Buff": ""
}
,
"BindMobile": {
"Buff": ""
}
,
"Status": 0,
"Sex": 0,
"PersonalCard": 0,
"Alias": "",
"HeadImgUpdateFlag": 0,
"HeadImgUrl": "",
"Signature": ""
}
,
"ContinueFlag": 0,
"SyncKey": {  #下一次去檢測需要的SyncKey,每當我們接受一次真正的消息或者長輪詢結束,原來的就失效,需要一個新的SyncKey值 "Count": 9,
"List": [{
"Key": 1,
"Val": 677540346
}
,{
"Key": 2,
"Val": 677540437
}
,{
"Key": 3,
"Val": 677540036
}
,{
"Key": 11,
"Val": 677540181
}
,{
"Key": 201,
"Val": 1529673345
}
,{
"Key": 203,
"Val": 1529658601
}
,{
"Key": 1000,
"Val": 1529658962
}
,{
"Key": 1001,
"Val": 1529659033
}
,{
"Key": 2001,
"Val": 1529480143
}
]
}
,
"SKey": "",
"SyncCheckKey": {
"Count": 9,
"List": [{
"Key": 1,
"Val": 677540346
}
,{
"Key": 2,
"Val": 677540437
}
,{
"Key": 3,
"Val": 677540036
}
,{
"Key": 11,
"Val": 677540181
}
,{
"Key": 201,
"Val": 1529673345
}
,{
"Key": 203,
"Val": 1529658601
}
,{
"Key": 1000,
"Val": 1529658962
}
,{
"Key": 1001,
"Val": 1529659033
}
,{
"Key": 2001,
"Val": 1529480143
}
]
}

}

 后台視圖方法獲取接收的信息

def get_msg(request):
    ret = {
        'code':400,
        'msg':'no message arrived'
    }
    global SYNCKEY_DICT  #設置為全局
    #1.先去查詢是否有消息到達
    req_url = 'https://webpush.wx.qq.com/cgi-bin/mmwebwx-bin/synccheck'
    sync_key = []
    for item in SYNCKEY_DICT['List']:
        sync_key.append("%s_%s"%(item['Key'],item['Val']))

    reponse = requests.get(
        url=req_url,
        params={
            'r':int(time.time()*1000),
            'skey':TICKET_DICT['skey'],
            'sid':TICKET_DICT['wxsid'],
            'uin':TICKET_DICT['wxuin'],
            'deviceid':'e055319847811019',
            'synckey':'|'.join(sync_key)  #參數重組
        },
        cookies = ALL_COOKIE_DICT
    )

    if 'window.synccheck={retcode:"0",selector:"2"}' in reponse.text:
        ret['code'] = 200
        ret['msg'] = "message arrived" #有消息到來,這時我們需要去獲取信息,並且更新SYNCKEY_DICT
        req_url = 'https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxsync'

        post_dict = {
            'BaseRequest':
                {
                    'DeviceID': "e055319847811019",
                    'Sid': TICKET_DICT['wxsid'],
                    'Skey': TICKET_DICT['skey'],
                    'Uin': TICKET_DICT['wxuin']
                },
            'SyncKey':SYNCKEY_DICT
        }

        reponse2 = requests.post(
            url=req_url,
            params={
                'sid':TICKET_DICT['wxsid'],
                'pass_ticket':TICKET_DICT['pass_ticket'],
                'skey':TICKET_DICT['skey'],
                'lang': 'zh_CN'
            },
            json = post_dict
        )

        reponse2.encoding = "utf-8"
        rep_dict = json.loads(reponse2.text)
        SYNCKEY_DICT = rep_dict.get("SyncKey")
        if rep_dict['AddMsgCount'] != 0:
            ret['code'] = 201
            ret['msg'] = []
            for item in rep_dict['AddMsgList']:
                ret['msg'].append(item)

    return HttpResponse(json.dumps(ret))

前端修改:首先是有get_msg方法去長輪詢獲取接收消息和檢測數據是否接收。然后針對誰發送的,誰就高亮

    <script>
    $(function(){
        bind_event();
        get_msg();
    })

    function bind_event() {
        $(".list-group-item").click(function(){
            $(".list-unstyled").empty();
            $(this).siblings().removeClass("active");
            $(this).addClass("active");
            var NickName = $(this).first().text().trim();
            $(".panel-title").text(NickName);
        })
    }

    function get_msg(){
        $.ajax({
            url:"/get-msg.html",
            type:"GET",
            dataType:"json",
            success:function(callback){
                if (callback.code==201){
                    //這里只去看一個人的信息
                    var info = callback['msg'][0]
                    $(".list-group-item").each(function(){
                        if($(this).attr("for")==info['FromUserName']){
                            $(this).addClass("active")
                            return false;
                        }
                    })
                }
                get_msg();
            }
        })
    }
    </script>
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link href="/static/css/bootstrap.min.css" rel="stylesheet">
    <link href="/static/css/nifty.min.css" rel="stylesheet">
    <link href="/static/css/demo/nifty-demo-icons.min.css" rel="stylesheet">
    <link href="/static/css/demo/nifty-demo.min.css" rel="stylesheet">
    <link href="/static/plugins/pace/pace.min.css" rel="stylesheet">
    <script src="/static/js/jquery-2.2.4.min.js"></script>
    <script>
    $(function(){
        bind_event();
        get_msg();
    })

    function bind_event() {
        $(".list-group-item").click(function(){
            $(".list-unstyled").empty();
            $(this).siblings().removeClass("active");
            $(this).addClass("active");
            var NickName = $(this).first().text().trim();
            $(".panel-title").text(NickName);
        })
    }

    function get_msg(){
        $.ajax({
            url:"/get-msg.html",
            type:"GET",
            dataType:"json",
            success:function(callback){
                if (callback.code==201){
                    //這里只去看一個人的信息
                    var info = callback['msg'][0]
                    $(".list-group-item").each(function(){
                        if($(this).attr("for")==info['FromUserName']){
                            $(this).addClass("active")
                            return false;
                        }
                    })
                }
                get_msg();
            }
        })
    }
    </script>
    <script src="/static/plugins/pace/pace.min.js"></script>
    <script src="/static/js/bootstrap.min.js"></script>
    <script src="/static/js/nifty.min.js"></script>
    <script src="/static/js/demo/nifty-demo.min.js"></script>
    <script src="/static/plugins/flot-charts/jquery.flot.min.js"></script>
    <script src="/static/plugins/flot-charts/jquery.flot.resize.min.js"></script>
    <script src="/static/plugins/gauge-js/gauge.min.js"></script>
    <script src="/static/plugins/skycons/skycons.min.js"></script>
    <script src="/static/plugins/easy-pie-chart/jquery.easypiechart.min.js"></script>
    <script src="/static/js/demo/widgets.js"></script>
</head>
<body>
<div id="container" class="effect  aside-bright mainnav-sm aside-right aside-in">
    <div class="boxed">
        <div id="content-container">
            <div class="row">
                <div class="col-md-8 col-lg-8 col-sm-8">

            <!--Chat widget-->
            <!--===================================================-->
            <div class="panel" style="height: 640px">
                <!--Heading-->
                <div class="panel-heading">
                    <h3 class="panel-title">Chat</h3>
                </div>

                <!--Widget body-->
                <div style="height:510px;padding-top:0px;" class="widget-body">
                    <div class="nano">
                        <div class="nano-content pad-all">
                            <ul class="list-unstyled media-block">
                                <li class="mar-btm">
                                    <div class="media-left">
                                        <img src="img/profile-photos/1.png" class="img-circle img-sm" alt="Profile Picture">
                                    </div>
                                    <div class="media-body pad-hor">
                                        <div class="speech">
                                            <a href="#" class="media-heading">Aaron Chavez</a>
                                            <p>Hello Lucy, how can I help you today ?</p>
                                            <p class="speech-time">
                                            <i class="demo-pli-clock icon-fw"></i>09:23AM
                                            </p>
                                        </div>
                                    </div>
                                </li>
                                <li class="mar-btm">
                                    <div class="media-right">
                                        <img src="img/profile-photos/8.png" class="img-circle img-sm" alt="Profile Picture">
                                    </div>
                                    <div class="media-body pad-hor speech-right">
                                        <div class="speech">
                                            <a href="#" class="media-heading">Lucy Doe</a>
                                            <p>Hi, I want to buy a new shoes.</p>
                                            <p class="speech-time">
                                                <i class="demo-pli-clock icon-fw"></i> 09:23AM
                                            </p>
                                        </div>
                                    </div>
                                </li>
                            </ul>
                        </div>
                    </div>

                    <!--Widget footer-->
                    <div class="panel-footer" style="height: 90px;">
                        <div class="row">
                            <div class="col-xs-9">
                                <input type="text" placeholder="Enter your text" class="form-control chat-input">
                            </div>
                            <div class="col-xs-3">
                                <button class="btn btn-primary btn-block" onclick="sendMsg(this);" type="submit">Send</button>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
            <!--===================================================-->
            <!--Chat widget-->

        </div>
                <div class="col-md-4 col-lg-4 col-sm-4">
                    <aside id="aside-container">
                <div id="aside">
                    <div class="nano has-scrollbar">
                        <div class="nano-content" tabindex="0" style="right: -17px;">

                            <!--Nav tabs-->
                            <!--================================-->
                            <ul class="nav nav-tabs nav-justified">
                                <li class="active">
                                    <a href="#demo-asd-tab-1" data-toggle="tab">
                                        <i class="demo-pli-speech-bubble-7"></i>
                                    </a>
                                </li>
                            </ul>
                            <!--================================-->
                            <!--End nav tabs-->

                            <!-- Tabs Content -->
                            <!--================================-->
                            <div class="tab-content">
                                <div class="tab-pane fade in active" id="demo-asd-tab-1">
                                    <p class="pad-hor text-semibold text-main">
                                        <span class="pull-right badge badge-success">{{ contact_info_list.MemberCount }}</span> Friends
                                    </p>

                                    <!--Works-->
                                    <div class="list-group bg-trans">
                                        {% for item in contact_info_list.MemberList %}
                                            <a href="#" for="{{ item.UserName }}" class="list-group-item">
                                                <span class="badge badge-purple badge-icon badge-fw pull-left"></span> {{ item.NickName }}
                                            </a>
                                        {% endfor %}
                                    </div>
                                </div>
                            </div>
                        </div>
                    <div class="nano-pane" style="display: none;"><div class="nano-slider" style="height: 4059px; transform: translate(0px, 0px);"></div></div></div>
                </div>
            </aside>
                </div>
            </div>
        </div>
    </div>
</div>
</body>
</html>

<script>
    function sendMsg(ths){
        var sel_tag = $(".list-group").find(".active")
        if(sel_tag.length==0){
            return false;
        }
        var msg = $(ths).parents(".panel-footer").find(".chat-input").val();
        var sendMsg={
            'ToUserName':sel_tag.attr("for"),
            'Type':1,
            'Content':msg,
            'csrfmiddlewaretoken':'{{ csrf_token }}'
        }

        $.ajax({
            url:"send-msg.html",
            data:sendMsg,
            type:"POST",
            dataType:"json",
            success:function(callback){
                if (callback.code==200){
                    var dt = new Date()
                    var now_time = dt.toLocaleString();

                    console.log(callback);
                    var li = '<li class="mar-btm"><div class="media-right"><img src="'+callback.headImgUrl+'" class="img-circle img-sm" alt="Profile Picture"></div>';
                    li += '<div class="media-body pad-hor speech-right"><div class="speech"><a href="#" class="media-heading">'+callback.username+'</a>';
                    li += '<p>'+msg+'</p>';
                    li += '<p class="speech-time">';
                    li += '<i class="demo-pli-clock icon-fw"></i>'+now_time;
                    li += '</p></div></div></li>';
                    $(ths).parents(".widget-body").find(".list-unstyled").append(li);
                    $(ths).parents(".panel-footer").find(".chat-input").val("");
                }
            }
        })
    }
</script>
contact_info前端代碼

window.synccheck={retcode:"0",selector:"2"}
{
"BaseResponse": {
"Ret": 0,
"ErrMsg": ""
}
,
"AddMsgCount": 1,
"AddMsgList": [{
"MsgId": "8087080836430146290",
"FromUserName": "@7ef22458145d7446b96c0c1612549c00991cab433640c86b9c7d5f9d17dc8a43",
"ToUserName": "@fb5a4e79e7d71ec3f11d3351fdec8a1cb5c4df7979041ed9315833e427323198",
"MsgType": 1,
"Content": "",
"Status": 3,
"ImgStatus": 1,
"CreateTime": 1529679858,
"VoiceLength": 0,
"PlayLength": 0,
"FileName": "",
"FileSize": "",
"MediaId": "",
"Url": "",
"AppMsgType": 0,
"StatusNotifyCode": 0,
"StatusNotifyUserName": "",
"RecommendInfo": {
"UserName": "",
"NickName": "",
"QQNum": 0,
"Province": "",
"City": "",
"Content": "",
"Signature": "",
"Alias": "",
"Scene": 0,
"VerifyFlag": 0,
"AttrStatus": 0,
"Sex": 0,
"Ticket": "",
"OpCode": 0
}
,
"ForwardFlag": 0,
"AppInfo": {
"AppID": "",
"Type": 0
}
,
"HasProductId": 0,
"Ticket": "",
"ImgHeight": 0,
"ImgWidth": 0,
"SubMsgType": 0,
"NewMsgId": 8087080836430146290,
"OriContent": "",
"EncryFileName": ""
}
],
"ModContactCount": 0,
"ModContactList": [],
"DelContactCount": 0,
"DelContactList": [],
"ModChatRoomMemberCount": 0,
"ModChatRoomMemberList": [],
"Profile": {
"BitFlag": 0,
"UserName": {
"Buff": ""
}
,
"NickName": {
"Buff": ""
}
,
"BindUin": 0,
"BindEmail": {
"Buff": ""
}
,
"BindMobile": {
"Buff": ""
}
,
"Status": 0,
"Sex": 0,
"PersonalCard": 0,
"Alias": "",
"HeadImgUpdateFlag": 0,
"HeadImgUrl": "",
"Signature": ""
}
,
"ContinueFlag": 0,
"SyncKey": {
"Count": 8,
"List": [{
"Key": 1,
"Val": 677540346
}
,{
"Key": 2,
"Val": 677540469
}
,{
"Key": 3,
"Val": 677540464
}
,{
"Key": 11,
"Val": 677540440
}
,{
"Key": 201,
"Val": 1529679858
}
,{
"Key": 1000,
"Val": 1529658962
}
,{
"Key": 1001,
"Val": 1529659033
}
,{
"Key": 2001,
"Val": 1529480143
}
]
}
,
"SKey": "",
"SyncCheckKey": {
"Count": 8,
"List": [{
"Key": 1,
"Val": 677540346
}
,{
"Key": 2,
"Val": 677540469
}
,{
"Key": 3,
"Val": 677540464
}
,{
"Key": 11,
"Val": 677540440
}
,{
"Key": 201,
"Val": 1529679858
}
,{
"Key": 1000,
"Val": 1529658962
}
,{
"Key": 1001,
"Val": 1529659033
}
,{
"Key": 2001,
"Val": 1529480143
}
]
}

}
后端打印的數據

其實應該更進一步,顯示出來我們接受的數據,但是明天考試..不再繼續了

八:全部代碼

后端:

from django.shortcuts import render,HttpResponse,redirect
from bs4 import BeautifulSoup
import requests
import time,re,json

CTIME = None
QCODE = None
TIP = 1
TICKET_DICT = {}    #保存憑證信息
ALL_COOKIE_DICT = {}    #保存所有COOKIE信息
USER_INIT_DICT = {} #保存用戶最近聯系信息,和自己的信息
SYNCKEY_DICT = {}    #用於保存獲取請求時需要的SyncKey


# Create your views here.
def login(request):
    global CTIME
    global QCODE
    CTIME = int(time.time()*1000)

    data = {
        'appid':'wx782c26e4c19acffb',
        'fun':'new',
        'lang':'zh_CN',
        '_':CTIME
    }

    response = requests.get(
        url="https://login.wx.qq.com/jslogin",
        params=data
    )

    pat_res = re.findall('uuid = "(.*)";',response.text)
    QCODE = pat_res[0]

    return render(request,"login.html",{'qcode':QCODE})

def check_login(request):
    global TIP
    ret = {'code':408,'data':None}
    data = {
        'loginicon':"true",
        'uuid':QCODE,
        'tip':TIP,
        'r':'-577317906',
        '_':int(time.time())
    }
    r1 = requests.get(
        url='https://login.wx.qq.com/cgi-bin/mmwebwx-bin/login',
        params=data
    )

    if 'window.code=408' in r1.text:
        print("無人掃描")
        return HttpResponse(json.dumps(ret))
    elif 'window.code=201' in r1.text:
        ret['code'] = 201
        pat_ret = re.findall("window.userAvatar = '(.*)';",r1.text)[0]
        ret['data'] = pat_ret
        TIP = 0
        return HttpResponse(json.dumps(ret))
    elif 'window.code=200;' in r1.text:
        ret['code'] = 200
        redirect_url = re.findall('window.redirect_uri="(.*)";', r1.text)[0]
        reponse = requests.get(     #獲取憑證,這里也開始設置cookie了,所以我們在這里向后需要記錄cookie
            url=redirect_url + "&fun=new&version=v2"  # url不夠完整,需要我們完善
        )
        ALL_COOKIE_DICT.update(reponse.cookies)

        soup = BeautifulSoup(reponse.text, "lxml")
        info_dict = {}
        for tag in soup.find("error").children:
            info_dict[tag.name] = tag.get_text()

        global TICKET_DICT
        TICKET_DICT.update(info_dict)

        ret['code']=200

        return HttpResponse(json.dumps(ret))


def user(request):
    get_user_info_url = 'https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxinit?r=-613135321&pass_ticket=' + TICKET_DICT[
        'pass_ticket']
    get_user_info_form = {
        'BaseRequest':
            {
                'DeviceID': "e055319847811019",
                'Sid': TICKET_DICT['wxsid'],
                'Skey': TICKET_DICT['skey'],
                'Uin': TICKET_DICT['wxuin']
            }
    }

    reponse2 = requests.post(  # 獲取的是用戶信息,幾個聯系人,公眾號,自己信息
        url=get_user_info_url,
        json=get_user_info_form,  # 注意這里使用的是json,post不允許傳送字典
    )
    ALL_COOKIE_DICT.update(reponse2.cookies)

    reponse2.encoding = "utf-8"

    user_info_dict = json.loads(reponse2.text)  # 獲取的是用戶信息,幾個聯系人,公眾號,自己信息
    USER_INIT_DICT.update(user_info_dict)
    SYNCKEY_DICT.update(user_info_dict['SyncKey'])

    return render(request, "user.html", {'user_info_dict': user_info_dict})


def contact_list(request):
    get_all_user_url = 'https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxgetcontact?lang=zh_CN&pass_ticket=%s&r=%s&seq=0&skey=%s' % (TICKET_DICT['pass_ticket'],int(time.time()*1000),TICKET_DICT['skey'])

    reponse = requests.get(
        url=get_all_user_url,   #這里需要用到cookie
        cookies=ALL_COOKIE_DICT
    )

    reponse.encoding = "utf-8"
    contact_info_list = json.loads(reponse.text)

    return render(request,"contact_info.html",{'contact_info_list':contact_info_list})

def send_msg(request):
    ret = {
        'code':200,
        'error':'Send Success',
        'data':{}
    }

    recv_data = request.POST

    if not recv_data:
        ret['code']=400
        ret['data']="Send failure"
        return HttpResponse(json.dumps(ret))

    #數據整合
    Send_data={}
    Send_data['BaseRequest'] = {
        'DeviceID': "e055319847811019",
        'Sid': TICKET_DICT['wxsid'],
        'Skey': TICKET_DICT['skey'],
        'Uin': TICKET_DICT['wxuin']
    }

    Send_data['Msg'] = {
        'Type':recv_data.get("Type",1),
        'Content':recv_data.get("Content"),
        'FromUserName':USER_INIT_DICT['User']['UserName'],
        'ToUserName':recv_data.get("ToUserName"),
        'LocalID':int(time.time()*1000),
        'ClientMsgId':int(time.time()*1000),
    }
    Send_data['Scene']=0

    send_url = 'https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxsendmsg?lang=zh_CN&pass_ticket=%s'%TICKET_DICT['pass_ticket']
    # reponse = requests.post(
    #     url=send_url,
    #     json=Send_data, #注意這里如果使用json,會將中文轉換為Unicode
    #     cookies=ALL_COOKIE_DICT
    # )
    reponse = requests.post(
        url=send_url,
        #若是有中文,需要加上ensure_ascii=False,若是字符串中含有中文,request傳遞數據時,將中文轉換為字節,無法為我們轉換。需要我們提前使用encoding編碼,直接傳遞字節,不讓requests為我們轉換
        #data可以是字典,字符串,字節,既然對於字典,字符串直接含有中文不正確,直接轉字節傳送,py3默認是utf-8,所以我們直接傳送字節就可以
        data=bytes(json.dumps(Send_data,ensure_ascii=False),encoding="utf-8"), #注意這里如果使用json,會將中文轉換為Unicode
        cookies=ALL_COOKIE_DICT
    )

    reponse.encoding = "utf-8"

    ret_status = re.findall('"Ret": (.*),', reponse.text)[0]
    ret_error = re.findall('"ErrMsg": "(.*)"', reponse.text)[0]

    if int(ret_status) != 0:
        ret['code']=401
        ret['data']=ret_error
        return HttpResponse(json.dumps(ret))

    ret['username'] = USER_INIT_DICT['User']['NickName']
    ret['headImgUrl'] = 'https://wx.qq.com'+USER_INIT_DICT['User']['HeadImgUrl']

    return HttpResponse(json.dumps(ret))

def get_msg(request):
    ret = {
        'code':400,
        'msg':'no message arrived'
    }
    global SYNCKEY_DICT
    #1.先去查詢是否有消息到達
    req_url = 'https://webpush.wx.qq.com/cgi-bin/mmwebwx-bin/synccheck'
    sync_key = []
    for item in SYNCKEY_DICT['List']:
        sync_key.append("%s_%s"%(item['Key'],item['Val']))

    reponse = requests.get(
        url=req_url,
        params={
            'r':int(time.time()*1000),
            'skey':TICKET_DICT['skey'],
            'sid':TICKET_DICT['wxsid'],
            'uin':TICKET_DICT['wxuin'],
            'deviceid':'e055319847811019',
            'synckey':'|'.join(sync_key)
        },
        cookies = ALL_COOKIE_DICT
    )

    if 'window.synccheck={retcode:"0",selector:"2"}' in reponse.text:
        ret['code'] = 200
        ret['msg'] = "message arrived"
        #有消息到來,這時我們需要去獲取信息,並且更新SYNCKEY_DICT
        req_url = 'https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxsync'

        post_dict = {
            'BaseRequest':
                {
                    'DeviceID': "e055319847811019",
                    'Sid': TICKET_DICT['wxsid'],
                    'Skey': TICKET_DICT['skey'],
                    'Uin': TICKET_DICT['wxuin']
                },
            'SyncKey':SYNCKEY_DICT
        }

        reponse2 = requests.post(
            url=req_url,
            params={
                'sid':TICKET_DICT['wxsid'],
                'pass_ticket':TICKET_DICT['pass_ticket'],
                'skey':TICKET_DICT['skey'],
                'lang': 'zh_CN'
            },
            json = post_dict
        )

        reponse2.encoding = "utf-8"
        rep_dict = json.loads(reponse2.text)
        SYNCKEY_DICT = rep_dict.get("SyncKey")
        if rep_dict['AddMsgCount'] != 0:
            ret['code'] = 201
            ret['msg'] = []
            for item in rep_dict['AddMsgList']:
                ret['msg'].append(item)

    return HttpResponse(json.dumps(ret))
views.py

前端:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<img id="qrcode" style="width: 340px;height: 340px;" src="https://login.weixin.qq.com/qrcode/{{ qcode }}" alt="">
</body>
</html>
<script src="/static/jquery.js"></script>
<script>
    $(function(){
        checkLogin();
    })

    function checkLogin() {
        $.ajax({
            url:'/check-login.html',
            type:'GET',
            dataType:"json",
            success:function(data){
                console.log(data.code);
                if (data.code==408){
                    checkLogin();
                }
                else if(data.code==201){
                    $("#qrcode").attr('src',data.data)
                    checkLogin();
                }
                else if(data.code==200){
                    location.href='/user.html'
                }
            }
        })
    }
</script>
login.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <div>
        <h3>最近聯系人</h3>
        <ul>
            {% for item in user_info_dict.ContactList %}
                <li>{{ item.NickName }}</li>
            {% endfor %}
        </ul>
        <a href="/contact-list.html">獲取更多聯系人</a>
    </div>
    <div>
        <h3>微信公眾號</h3>
        <div>
            {% for item in user_info_dict.MPSubscribeMsgList %}
                <h4>{{ item.NickName }}</h4>
                <ul>
                    {% for item2 in item.MPArticleList %}
                        <li>
                            <a href="{{ item2.Url }}">
                                {{ item2.Title }}
                            </a>
                        </li>
                    {% endfor %}
                </ul>
            {% endfor %}
        </div>
    </div>
</body>
</html>
user.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link href="/static/css/bootstrap.min.css" rel="stylesheet">
    <link href="/static/css/nifty.min.css" rel="stylesheet">
    <link href="/static/css/demo/nifty-demo-icons.min.css" rel="stylesheet">
    <link href="/static/css/demo/nifty-demo.min.css" rel="stylesheet">
    <link href="/static/plugins/pace/pace.min.css" rel="stylesheet">
    <script src="/static/js/jquery-2.2.4.min.js"></script>
    <script>
    $(function(){
        bind_event();
        get_msg();
    })

    function bind_event() {
        $(".list-group-item").click(function(){
            $(".list-unstyled").empty();
            $(this).siblings().removeClass("active");
            $(this).addClass("active");
            var NickName = $(this).first().text().trim();
            $(".panel-title").text(NickName);
        })
    }

    function get_msg(){
        $.ajax({
            url:"/get-msg.html",
            type:"GET",
            dataType:"json",
            success:function(callback){
                if (callback.code==201){
                    //這里只去看一個人的信息
                    var info = callback['msg'][0]
                    $(".list-group-item").each(function(){
                        if($(this).attr("for")==info['FromUserName']){
                            $(this).addClass("active")
                            return false;
                        }
                    })
                }
                get_msg();
            }
        })
    }
    </script>
    <script src="/static/plugins/pace/pace.min.js"></script>
    <script src="/static/js/bootstrap.min.js"></script>
    <script src="/static/js/nifty.min.js"></script>
    <script src="/static/js/demo/nifty-demo.min.js"></script>
    <script src="/static/plugins/flot-charts/jquery.flot.min.js"></script>
    <script src="/static/plugins/flot-charts/jquery.flot.resize.min.js"></script>
    <script src="/static/plugins/gauge-js/gauge.min.js"></script>
    <script src="/static/plugins/skycons/skycons.min.js"></script>
    <script src="/static/plugins/easy-pie-chart/jquery.easypiechart.min.js"></script>
    <script src="/static/js/demo/widgets.js"></script>
</head>
<body>
<div id="container" class="effect  aside-bright mainnav-sm aside-right aside-in">
    <div class="boxed">
        <div id="content-container">
            <div class="row">
                <div class="col-md-8 col-lg-8 col-sm-8">

            <!--Chat widget-->
            <!--===================================================-->
            <div class="panel" style="height: 640px">
                <!--Heading-->
                <div class="panel-heading">
                    <h3 class="panel-title">Chat</h3>
                </div>

                <!--Widget body-->
                <div style="height:510px;padding-top:0px;" class="widget-body">
                    <div class="nano">
                        <div class="nano-content pad-all">
                            <ul class="list-unstyled media-block">
                                <li class="mar-btm">
                                    <div class="media-left">
                                        <img src="img/profile-photos/1.png" class="img-circle img-sm" alt="Profile Picture">
                                    </div>
                                    <div class="media-body pad-hor">
                                        <div class="speech">
                                            <a href="#" class="media-heading">Aaron Chavez</a>
                                            <p>Hello Lucy, how can I help you today ?</p>
                                            <p class="speech-time">
                                            <i class="demo-pli-clock icon-fw"></i>09:23AM
                                            </p>
                                        </div>
                                    </div>
                                </li>
                                <li class="mar-btm">
                                    <div class="media-right">
                                        <img src="img/profile-photos/8.png" class="img-circle img-sm" alt="Profile Picture">
                                    </div>
                                    <div class="media-body pad-hor speech-right">
                                        <div class="speech">
                                            <a href="#" class="media-heading">Lucy Doe</a>
                                            <p>Hi, I want to buy a new shoes.</p>
                                            <p class="speech-time">
                                                <i class="demo-pli-clock icon-fw"></i> 09:23AM
                                            </p>
                                        </div>
                                    </div>
                                </li>
                            </ul>
                        </div>
                    </div>

                    <!--Widget footer-->
                    <div class="panel-footer" style="height: 90px;">
                        <div class="row">
                            <div class="col-xs-9">
                                <input type="text" placeholder="Enter your text" class="form-control chat-input">
                            </div>
                            <div class="col-xs-3">
                                <button class="btn btn-primary btn-block" onclick="sendMsg(this);" type="submit">Send</button>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
            <!--===================================================-->
            <!--Chat widget-->

        </div>
                <div class="col-md-4 col-lg-4 col-sm-4">
                    <aside id="aside-container">
                <div id="aside">
                    <div class="nano has-scrollbar">
                        <div class="nano-content" tabindex="0" style="right: -17px;">

                            <!--Nav tabs-->
                            <!--================================-->
                            <ul class="nav nav-tabs nav-justified">
                                <li class="active">
                                    <a href="#demo-asd-tab-1" data-toggle="tab">
                                        <i class="demo-pli-speech-bubble-7"></i>
                                    </a>
                                </li>
                            </ul>
                            <!--================================-->
                            <!--End nav tabs-->

                            <!-- Tabs Content -->
                            <!--================================-->
                            <div class="tab-content">
                                <div class="tab-pane fade in active" id="demo-asd-tab-1">
                                    <p class="pad-hor text-semibold text-main">
                                        <span class="pull-right badge badge-success">{{ contact_info_list.MemberCount }}</span> Friends
                                    </p>

                                    <!--Works-->
                                    <div class="list-group bg-trans">
                                        {% for item in contact_info_list.MemberList %}
                                            <a href="#" for="{{ item.UserName }}" class="list-group-item">
                                                <span class="badge badge-purple badge-icon badge-fw pull-left"></span> {{ item.NickName }}
                                            </a>
                                        {% endfor %}
                                    </div>
                                </div>
                            </div>
                        </div>
                    <div class="nano-pane" style="display: none;"><div class="nano-slider" style="height: 4059px; transform: translate(0px, 0px);"></div></div></div>
                </div>
            </aside>
                </div>
            </div>
        </div>
    </div>
</div>
</body>
</html>

<script>
    function sendMsg(ths){
        var sel_tag = $(".list-group").find(".active")
        if(sel_tag.length==0){
            return false;
        }
        var msg = $(ths).parents(".panel-footer").find(".chat-input").val();
        var sendMsg={
            'ToUserName':sel_tag.attr("for"),
            'Type':1,
            'Content':msg,
            'csrfmiddlewaretoken':'{{ csrf_token }}'
        }

        $.ajax({
            url:"send-msg.html",
            data:sendMsg,
            type:"POST",
            dataType:"json",
            success:function(callback){
                if (callback.code==200){
                    var dt = new Date()
                    var now_time = dt.toLocaleString();

                    console.log(callback);
                    var li = '<li class="mar-btm"><div class="media-right"><img src="'+callback.headImgUrl+'" class="img-circle img-sm" alt="Profile Picture"></div>';
                    li += '<div class="media-body pad-hor speech-right"><div class="speech"><a href="#" class="media-heading">'+callback.username+'</a>';
                    li += '<p>'+msg+'</p>';
                    li += '<p class="speech-time">';
                    li += '<i class="demo-pli-clock icon-fw"></i>'+now_time;
                    li += '</p></div></div></li>';
                    $(ths).parents(".widget-body").find(".list-unstyled").append(li);
                    $(ths).parents(".panel-footer").find(".chat-input").val("");
                }
            }
        })
    }
</script>
contact_info.html

需要:nifty插件可以聯系我


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM