【Python之路】特別篇--微信Web網頁版通訊的全過程分析

 

  文章所使用Python版本爲py3.5html

1.微信服務器返回一個會話ID前端

微信Web版本不使用用戶名和密碼直接登陸,而是採用二維碼登陸,因此服務器須要首先分配一個惟一的會話ID,用來標識當前的一次登陸。python

經過查看網絡請求咱們找到了這個 二維碼圖片表明的隨機字符串,(IcelandB9Entig==),jquery

2.經過會話ID得到二維碼web

而後找到該隨機字符串的來源請求ajax

請求方式爲 GET形式 , 具體鏈接爲:json

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
&_=1492591577859

咱們只須要改變最後一個變量 _值便可得到新的字符串序列: (這個值是當前距離林威治標準時間的毫秒)能夠自行構造!服務器

經過分割,咱們就能夠得到隨機字符串,本身在前端頁面上構造一個二維碼出來.微信

import tornado.ioloop
import tornado.web
import requests
import time
import re
import json
import urllib.request,urllib.parse
import random

WECHAT_SESSION_ID = None
WECHAT_TIMESPAN = None

SESSION_ID_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}'

class HomeHandler(tornado.web.RequestHandler):
    def get(self):
        print('\n--------------------')
        global WECHAT_SESSION_ID
        global WECHAT_TIMESPAN

        WECHAT_TIMESPAN = str(time.time())
        sesssion_url = SESSION_ID_URL.format(WECHAT_TIMESPAN)
        response = requests.get(sesssion_url)
        # 獲取驗證碼,隨機字段
        WECHAT_SESSION_ID = re.split('=', response.text, 2)[-1].strip().replace('"', '').replace(';', '')
        print('Session_id : ',WECHAT_SESSION_ID)
        self.render('index.html',session_id = WECHAT_SESSION_ID)
HomeHandle
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
        body{
            margin: 0;
            padding: 0;
        }
        .login_alt{
            margin: 42px auto;
            text-align: center;
        }
        .image{
            display: block;
            width: 270px;
            height: 270px;
            margin: 42px auto;
        }
    </style>
</head>
<body>

    <div class="login_alt"><h1>二維碼登錄</h1></div>

    <img src="https://login.weixin.qq.com/qrcode/{{session_id}}" class="image">

    <script src="{{ static_url('js/jquery-2.1.4.min.js')}}" ></script>
    <script>
        $(function () {
            acquire_image();
        });
        function acquire_image() {
            $.ajax({
                url:'/login',
                type:'POST',
                success:function (data) {
                    if(data == '200'){
                        window.location.href = "/index";
                    }
                    else{
                        acquire_image();
                    }

                },
                error:function (data) {
                    console.log('error');
                }
            })
        }
    </script>
</body>
</html>
前端二維碼頁面

3.輪詢手機端是否已經掃描二維碼並確認在Web端登陸cookie

當咱們還沒進行掃碼登陸時,發現微信web網頁會自動向服務器 輪詢手機端是否已經掃碼而且確認登陸!!

每一分鐘發送一次,若是沒有登陸,請求會返回

window.code=408;

掃碼後爲

window.code=201;

確認登錄後爲:

window.code=200;
window.redirect_uri="https://wx2.qq.com/cgi-bin/mmwebwx-bin/webwxnewloginpage?ticket=A_ToQqd_AFXpsrLMH6RNgi3W@qrticket_0&uuid=we6XJEZYDg==&lang=zh_CN&scan=1492592531";

須要得到其中的跳轉url,對rensponse進行分割後取得。

redirect_url = re.split('=', http_res_code.text, 2)[-1].strip().replace('"', '').replace(';', '')

4.訪問登陸地址,得到uin和sid

在接下來的鏈接中,咱們發現服務器發給了咱們skey,sid,pass_ticket 的重要信息, 分析發現該請求的發送地址爲: GET方式,

https://wx2.qq.com/cgi-bin/mmwebwx-bin/webwxnewloginpage?ticket=A_ToQqd_AFXpsrLMH6RNgi3W@qrticket_0&uuid=we6XJEZYDg==&lang=zh_CN&scan=1492592531
&fun=new&version=v2

發現,該請求地址爲 跳轉url + &fun=new&version=v2 構造而成!

直接GET發送請求,咱們就拿到返回信息,發現是 xml 格式的數據!

構造一個方法方便獲取咱們的鏈接信息

def auth_analysis(self,str_xml):
    '''
    xml中取出數據,返回字典
    :param http_res_ticket:
    :return:
    '''
    from xml.etree import ElementTree as ET
    root = ET.XML(str_xml)
    ret = {}
    for child in root:
        ret[child.tag] = child.text
    return ret

咱們還須要得到該請求下的cookies參數,直接經過requests模塊的  requests.cookies.get_dict()

# 獲取xml 登陸信息
user_ticket_url  = redirect_url+ '&fun=new&version=v2'
user_xml_ticket = requests.get(user_ticket_url)

TICKET_COOKIR = user_xml_ticket.cookies.get_dict()
ALL_COOKIE_DICT.update(TICKET_COOKIR)       #記錄cookies

# 獲取xml中信息
user_ticket_dic = self.auth_analysis(user_xml_ticket.text)
USER_RESULT_DICT.update(user_ticket_dic)      #記錄xml中的具體信息

5.初使化微信信息

# 初始化Url :
USER_INIT_URL = 'https://wx2.qq.com/cgi-bin/mmwebwx-bin/webwxinit?pass_ticket={0}&skey={1}&r={2}'

pass_ticket,skey爲上一步驟得到的xml信息樹中,r爲時間戳

# 初始化準備
user_init_payload = {
    'BaseRequest': {
        'DeviceID': 'e' + repr(random.random())[2:17],
        'Sid': USER_RESULT_DICT['wxsid'],
        'Skey': USER_RESULT_DICT['skey'],
        'Uin': int(USER_RESULT_DICT['wxuin']),
    }
}
# 初始化url
user_init_url = USER_INIT_URL.format(USER_RESULT_DICT['pass_ticket'],USER_RESULT_DICT['skey'],int(time.time()))

# payload 轉換成bytes
data = (json.dumps(user_init_payload)).encode()

request = urllib.request.Request(url=user_init_url, data=data)
request.add_header(
    'ContentType', 'application/json; charset=UTF-8')

response = urllib.request.urlopen(request)
data = response.read()
# 得到初始化用戶數據..
obj = json.loads(data.decode('utf-8'))
INIT_RESULT_DICT.update(obj)
View Code

這一步的發送請求,使用了urllib.requests來發送,注意格式轉換!

此時咱們已經得到了服務端返回的部分數據.若是須要進一步獲取所有信息,......以下

6.得到全部的好友列表

該請求返回了所有的用戶信息.

https://wx2.qq.com/cgi-bin/mmwebwx-bin/webwxgetcontact?
pass_ticket=YK57xcgn4qT0n0qoGtxvtLvsV6XXzTDka7Z9DOFAIcGDK0wtZ6GrNpGdHGIHKiiu
&r=1492592546748
&seq=0
&skey=@crypt_8226323c_fd634988b8e43769cb3b7b9fc99ca549

構造請求併發送:

class ContactHandler(tornado.web.RequestHandler):
    def get(self, *args, **kwargs):
        try:
            user_list_url = "https://wx2.qq.com/cgi-bin/mmwebwx-bin/webwxgetcontact?pass_ticket={0}&r={1}&seq=0&skey={2}"
            user_list_url = user_list_url.format(USER_RESULT_DICT['pass_ticket'],USER_RESULT_DICT['skey'],int(time.time()))

            conn = requests.get(url = user_list_url , data={} , cookies=ALL_COOKIE_DICT , headers={'contentType':'application/json; charset=UTF-8','Referer':'https://wx.qq.com/?&lang=zh_CN'})
            # print(conn.encoding)  # ISO-8859-1
            conn.encoding = 'utf-8'
            USER_LIST_DICT.update(json.loads(conn.text))
            # print(USER_LIST_DICT)

            self.render('contact_list.html', user_list_dict=USER_LIST_DICT, user=CURRENT_USER)
        except Exception:
            self.redirect('/login')
得到全部信息的handler

7.保持與服務器的信息同步

與服務器保持同步須要在客戶端作輪詢,該輪詢的URL以下:

https://webpush.wx2.qq.com/cgi-bin/mmwebwx-bin/synccheck?
r=1492594498787
&skey=%40crypt_8226323c_fd634988b8e43769cb3b7b9fc99ca549
&sid=mM%2BFZGbHxGcO3x93
&uin=976834800
&deviceid=e738560216565557
&synckey=1_661566297%7C2_661566394%7C3_661565574%7C11_661566180%7C13_661374753%7C201_1492594315%7C203_1492582669%7C1000_1492594202%7C1001_1492563271
&_=1492592515065

skey,sid,uin,與上面步驟的值相對應此處的synkey是上步步驟得到的同步鍵值,但須要按必定的規則組合成如下的字符串:

1_124125|2_452346345|3_65476547|1000_5643635 

sync_data_list = []
for item in INIT_RESULT_DICT['SyncKey']['List']:
    temp = "%s_%s" % (item['Key'], item['Val'])
    sync_data_list.append(temp)
sync_data_str = "|".join(sync_data_list)
合成synckey

| 被URL編碼成%7C,經過對上面的地址發送請求:,

res_sync = requests.get(synccheck_url,params=payloads,cookies = ALL_COOKIE_DICT)

會返回以下的字符串:

window.synccheck={retcode:"0",selector:"0"}

當有人發送信息給你時, :

window.synccheck={retcode:"0",selector:"2"}

8.得到別人發來的消息

咱們經過該URL地址獲取發送給咱們的消息:

https://wx2.qq.com/cgi-bin/mmwebwx-bin/webwxsync?
sid=XQvf1MmZ7W8O2BU2
&skey=@crypt_75efaa00_3afa77c01d45461eef7eac88da37f70d
&pass_ticket=YArFw%252BDpJHCpRtKCTTabpe2ytETBDmYsp%252BB7ywe%252BtplmzxQZ6ohX7d14sJgjgk6T

製造相應的payload 發送GET請求,得到返回response數據

if 'selector:"2"' in res_sync.text:

    fetch_msg_url = 'https://wx2.qq.com/cgi-bin/mmwebwx-bin/webwxsync?sid={0}&skey={1}&pass_ticket={2}'
    fetch_msg_url = fetch_msg_url.format(USER_RESULT_DICT['wxsid'],USER_RESULT_DICT['skey'],USER_RESULT_DICT['pass_ticket'])

    payloads = {
        'BaseRequest': {
            'DeviceID': 'e' + repr(random.random())[2:17],
            'Sid': USER_RESULT_DICT['wxsid'],
            'Skey': USER_RESULT_DICT['skey'],
            'Uin': int(USER_RESULT_DICT['wxuin']),
        },
        'SyncKey' : INIT_RESULT_DICT['SyncKey'],
        'rr' : int(time.time())
    }

    # payload 轉換成bytes
    data = (json.dumps(payloads)).encode()

    request = urllib.request.Request(url=fetch_msg_url, data=data)
    request.add_header(
        'ContentType', 'application/json; charset=UTF-8')

    response = urllib.request.urlopen(request)
    data = response.read()

    # 得到初始化用戶數據..
    res_fetch_msg_dict = json.loads(data.decode('utf-8'))
    INIT_RESULT_DICT['SyncKey'] = res_fetch_msg_dict['SyncKey']

    for item in res_fetch_msg_dict['AddMsgList']:
        print(item['FromUserName'], "---->", item['ToUserName'], ":::::", item['Content'])
View Code

9.向用戶發送消息

用戶主動發送消息,經過如下的URL地址:

https://wx2.qq.com/cgi-bin/mmwebwx-bin/webwxsendmsg
?pass_ticket=mRfzOKMZdUAfqrZVaT7VZeroYNX6SgTtO7WzDwDXmiZvwWC0iWlln2fBuGa8oeld

上面的pass_ticket參數再也不解釋了,訪問該URL採用POST方式,payload如如下的格式:

message = self.get_argument('message')         # 須要發送的信息
to_username = self.get_argument('username')    # 接收人的id  好友列表中獲取
print(message,to_username) 
#
send_url = 'https://wx2.qq.com/cgi-bin/mmwebwx-bin/webwxsendmsg?pass_ticket={0}'
send_url = send_url.format(USER_RESULT_DICT['pass_ticket'])
time_str = str(int(time.time()))
payloads = {
    'BaseRequest': {
        'DeviceID': 'e' + repr(random.random())[2:17],
        'Sid': USER_RESULT_DICT['wxsid'],
        'Skey': USER_RESULT_DICT['skey'],
        'Uin': int(USER_RESULT_DICT['wxuin']),
    },
    'Msg': {
        'ClientMsgId': time_str,
        'Content': message,
        'FromUserName': CURRENT_USER['UserName'],     # 本身的用戶信息,在微信初始化時得到!
        'LocalID': time_str,
        'ToUserName': to_username,
        'Type': 1,
    },
    'Scene': 0,
}

# payload 轉換成bytes
data = (json.dumps(payloads)).encode()
request = urllib.request.Request(url=send_url, data=data)
request.add_header(
    'ContentType', 'application/json; charset=UTF-8')

response = urllib.request.urlopen(request)
data = response.read()

# 得到初始化用戶數據..
res_fetch_msg_dict = json.loads(data.decode('utf-8'))

print(res_fetch_msg_dict)
View Code

  BaseRequest都是受權相關的值,與上面的步驟中的值對應,Msg是對消息的描述,包括了發送人與接收人,消息內容,消息的類型(1爲文本),ClientMsgId和LocalID由本地生成。rr可用當前的時間。在返回JSON結果中BaseResponse描述了發送狀況,Ret爲0表示發送成功。

 

 

注意:

該流程在py3環境下,使用了Tornado框架 和 requests 包 和 urllib.requests 包

urllib.requests 包 具體用法參考以下示例:

# payload 轉換成bytes
data = (json.dumps(payload)).encode()

request = urllib.request.Request(url=user_init_url, data=data)
request.add_header(
    'ContentType', 'application/json; charset=UTF-8')

response = urllib.request.urlopen(request)
# 得到數據
data = response.read()
obj = json.loads(data.decode('utf-8'))
# 保存數據
INIT_RESULT_DICT.update(obj)

  

完整參考代碼:

#!/usr/bin/env python
# -*-coding:utf-8 -*-


import tornado.ioloop
import tornado.web

from controllers import index


settings = {
    'template_path': 'views',    # 模版路徑的配置
    'static_path' : 'static',       # 靜態文件路徑
}

application = tornado.web.Application([
    (r"/home", index.HomeHandler),
    (r"/login", index.LoginHandler),
    (r"/index", index.IndexHandler),
    (r"/contact_list", index.ContactHandler),
    (r"/msg", index.MessageGetHandler),
    (r"/test", index.TestHandler),
],**settings)

if __name__ == "__main__":
    print('http://localhost:8888/home')
    application.listen(8888)
    tornado.ioloop.IOLoop.instance().start()
app.py
#!/usr/bin/env python
# -*-coding:utf-8 -*-

import tornado.ioloop
import tornado.web
import requests
import time
import re
import json
import urllib.request
import random
import copy

WECHAT_SESSION_ID = None
WECHAT_TIMESPAN = None

SESSION_ID_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}'

LOGIN_URL = 'https://login.wx.qq.com/cgi-bin/mmwebwx-bin/login?loginicon=true&uuid={0}&tip=1&r=-1910008125&_={1}'


# 登陸信息 :
USER_INFO_URL = 'https://wx2.qq.com/cgi-bin/mmwebwx-bin/webwxnewloginpage?ticket={0}&uuid={1}&lang=zh_CN&scan=1492317317&fun=new&version=v2'

# 'https://wx2.qq.com/cgi-bin/mmwebwx-bin/webwxnewloginpage?ticket=A_efO6sZQDqimyL-Cybhd6G8@qrticket_0&uuid=AanPHT1H9w==&lang=zh_CN&scan=1492317317&fun=new&version=v2'

# 初始化 :
USER_INIT_URL = 'https://wx2.qq.com/cgi-bin/mmwebwx-bin/webwxinit?pass_ticket={0}&skey={1}&r={2}'

# https://wx2.qq.com/cgi-bin/mmwebwx-bin/webwxinit?r=-1964927750&pass_ticket=u%252BqG9nArZmFOEieyz9dA0i7f4kSKwRxnM9O5KgBtOp8Z5FSVKGKrNmTrKOBTl0Ml


BASE_REQUEST_DICT = {}

INIT_RESULT_DICT = {}

USER_RESULT_DICT = {}

CURRENT_USER = {}

USER_LIST_DICT = {}

ALL_COOKIE_DICT = {}

class HomeHandler(tornado.web.RequestHandler):
    def get(self):
        print('\n--------------------')
        global WECHAT_SESSION_ID
        global WECHAT_TIMESPAN

        WECHAT_TIMESPAN = str(time.time())
        sesssion_url = SESSION_ID_URL.format(WECHAT_TIMESPAN)
        response = requests.get(sesssion_url)
        # 獲取驗證碼,隨機字段
        WECHAT_SESSION_ID = re.split('=', response.text, 2)[-1].strip().replace('"', '').replace(';', '')
        print('Session_id : ',WECHAT_SESSION_ID)
        self.render('index.html',session_id = WECHAT_SESSION_ID)


class LoginHandler(tornado.web.RequestHandler):

    def auth_analysis(self,str_xml):
        '''
        xml中取出數據,返回字典
        :param http_res_ticket:
        :return:
        '''
        from xml.etree import ElementTree as ET
        root = ET.XML(str_xml)
        ret = {}
        for child in root:
            ret[child.tag] = child.text
        return ret

    def post(self):
        ret_code = "201"
        login_url = LOGIN_URL.format(WECHAT_SESSION_ID,str(time.time()))

        http_res_code = requests.get(login_url)

        if "window.code=408" in http_res_code.text:
            ret_code = "408"
        if "window.code=200" in http_res_code.text:
            ret_code = "200"

            # 登陸跳轉URL
            redirect_url = re.split('=', http_res_code.text, 2)[-1].strip().replace('"', '').replace(';', '')
            print('200 : 跳轉url',redirect_url)

            code_cookie = http_res_code.cookies.get_dict()
            ALL_COOKIE_DICT.update(code_cookie)
            print('cookies 1 login:', ALL_COOKIE_DICT)

            # 獲取xml 登陸信息
            user_ticket_url  = redirect_url+ '&fun=new&version=v2'
            user_xml_ticket = requests.get(user_ticket_url)

            TICKET_COOKIR = user_xml_ticket.cookies.get_dict()
            ALL_COOKIE_DICT.update(TICKET_COOKIR)
            print('cookies 2 xml:',ALL_COOKIE_DICT)

            xml_str = user_xml_ticket.text
            # 獲取xml中信息
            user_ticket_dic = self.auth_analysis(xml_str)

            USER_RESULT_DICT.update(user_ticket_dic)

            # 初始化準備
            # __init__ payload :
            user_init_payload = {
                'BaseRequest': {
                    'DeviceID': 'e' + repr(random.random())[2:17],
                    'Sid': USER_RESULT_DICT['wxsid'],
                    'Skey': USER_RESULT_DICT['skey'],
                    'Uin': int(USER_RESULT_DICT['wxuin']),
                }
            }

            BASE_REQUEST_DICT.update(user_init_payload)

            # 初始化url
            user_init_url = USER_INIT_URL.format(USER_RESULT_DICT['pass_ticket'],USER_RESULT_DICT['skey'],int(time.time()))

            # payload 轉換成bytes
            data = (json.dumps(user_init_payload)).encode()

            request = urllib.request.Request(url=user_init_url, data=data)
            request.add_header(
                'ContentType', 'application/json; charset=UTF-8')

            response = urllib.request.urlopen(request)
            data = response.read()
            # 得到初始化用戶數據..
            obj = json.loads(data.decode('utf-8'))
            INIT_RESULT_DICT.update(obj)


            # print('response : ' ,type(obj))
            # print('--',INIT_RESULT_DICT)

        print(ret_code)
        self.write(ret_code)

class IndexHandler(tornado.web.RequestHandler):
    def get(self):
        print(INIT_RESULT_DICT)
        print('--------------')
        print(INIT_RESULT_DICT['SyncKey'])
        try:
            count = INIT_RESULT_DICT['Count']
            sync_key = INIT_RESULT_DICT['SyncKey']
            system_time = INIT_RESULT_DICT['SystemTime']
            skey = INIT_RESULT_DICT['SKey']

            client_version = INIT_RESULT_DICT['ClientVersion']
            base_response = INIT_RESULT_DICT['BaseResponse']
            MPSubscribeMsgCount = INIT_RESULT_DICT['MPSubscribeMsgCount']
            GrayScale = INIT_RESULT_DICT['GrayScale']
            InviteStartCount = INIT_RESULT_DICT['InviteStartCount']

            MPSubscribeMsgList = INIT_RESULT_DICT['MPSubscribeMsgList']

            ClickReportInterval = INIT_RESULT_DICT['ClickReportInterval']

            contact_list = INIT_RESULT_DICT['ContactList']

            user = INIT_RESULT_DICT['User']
            CURRENT_USER.update(user)

            self.render('main.html', user=user, contact_list=contact_list, MPSubscribeMsgList=MPSubscribeMsgList)
        except Exception as e:
            print(e)
            self.redirect('/login')

class ContactHandler(tornado.web.RequestHandler):
    def get(self, *args, **kwargs):
        try:
            user_list_url = "https://wx2.qq.com/cgi-bin/mmwebwx-bin/webwxgetcontact?pass_ticket={0}&r={1}&seq=0&skey={2}"
            user_list_url = user_list_url.format(USER_RESULT_DICT['pass_ticket'],USER_RESULT_DICT['skey'],int(time.time()))
            # print(user_list_url)
            conn = requests.get(url = user_list_url , data={} , cookies=ALL_COOKIE_DICT , headers={'contentType':'application/json; charset=UTF-8','Referer':'https://wx.qq.com/?&lang=zh_CN'})
            # print(conn.encoding)  # ISO-8859-1
            conn.encoding = 'utf-8'
            USER_LIST_DICT.update(json.loads(conn.text))
            # print(USER_LIST_DICT)

            self.render('contact_list.html', user_list_dict=USER_LIST_DICT, user=CURRENT_USER)
        except Exception:
            self.redirect('/login')

class MessageGetHandler(tornado.web.RequestHandler):
    def get(self):
        global INIT_RESULT_DICT

        synccheck_url = 'https://webpush.wx2.qq.com/cgi-bin/mmwebwx-bin/synccheck'
        sync_data_list = []
        for item in INIT_RESULT_DICT['SyncKey']['List']:
            temp = "%s_%s" % (item['Key'], item['Val'])
            sync_data_list.append(temp)
        sync_data_str = "|".join(sync_data_list)

        payloads = {
            "r" : int(time.time()),
            "skey" : USER_RESULT_DICT['skey'],
            "sid" : USER_RESULT_DICT['wxsid'],
            "uin" : USER_RESULT_DICT['wxuin'],
            "devicedid" : 'e' + repr(random.random())[2:17],
            "synckey" : sync_data_str,
        }

        res_sync = requests.get(synccheck_url,params=payloads,cookies = ALL_COOKIE_DICT)
        print('Status: ', res_sync.text)

        if 'selector:"2"' in res_sync.text:

            fetch_msg_url = 'https://wx2.qq.com/cgi-bin/mmwebwx-bin/webwxsync?sid={0}&skey={1}&pass_ticket={2}'
            fetch_msg_url = fetch_msg_url.format(USER_RESULT_DICT['wxsid'],USER_RESULT_DICT['skey'],USER_RESULT_DICT['pass_ticket'])

            payloads = {
                'BaseRequest': {
                    'DeviceID': 'e' + repr(random.random())[2:17],
                    'Sid': USER_RESULT_DICT['wxsid'],
                    'Skey': USER_RESULT_DICT['skey'],
                    'Uin': int(USER_RESULT_DICT['wxuin']),
                },
                'SyncKey' : INIT_RESULT_DICT['SyncKey'],
                'rr' : int(time.time())
            }

            # payload 轉換成bytes
            data = (json.dumps(payloads)).encode()


            # fetch_msg_data = copy.deepcopy(BASE_REQUEST_DICT)
            # fetch_msg_data['SyncKey'] = INIT_RESULT_DICT['SyncKey']
            # fetch_msg_data['rr'] = int(time.time())

            request = urllib.request.Request(url=fetch_msg_url, data=data)
            request.add_header(
                'ContentType', 'application/json; charset=UTF-8')

            response = urllib.request.urlopen(request)
            data = response.read()
            # 得到初始化用戶數據..
            res_fetch_msg_dict = json.loads(data.decode('utf-8'))
            INIT_RESULT_DICT['SyncKey'] = res_fetch_msg_dict['SyncKey']

            for item in res_fetch_msg_dict['AddMsgList']:
                print(item['FromUserName'], "---->", item['ToUserName'], ":::::", item['Content'])
            self.write("ok")




    def post(self, *args, **kwargs):

        message = self.get_argument('message')
        to_username = self.get_argument('username')
        print(message,to_username)
        #
        send_url = 'https://wx2.qq.com/cgi-bin/mmwebwx-bin/webwxsendmsg?pass_ticket={0}'
        send_url = send_url.format(USER_RESULT_DICT['pass_ticket'])
        time_str = str(int(time.time()))
        payloads = {
            'BaseRequest': {
                'DeviceID': 'e' + repr(random.random())[2:17],
                'Sid': USER_RESULT_DICT['wxsid'],
                'Skey': USER_RESULT_DICT['skey'],
                'Uin': int(USER_RESULT_DICT['wxuin']),
            },
            'Msg': {
                'ClientMsgId': time_str,
                'Content': message,
                'FromUserName': CURRENT_USER['UserName'],
                'LocalID': time_str,
                'ToUserName': to_username,
                'Type': 1,
            },
            'Scene': 0,
        }

        # payload 轉換成bytes
        data = (json.dumps(payloads)).encode()
        request = urllib.request.Request(url=send_url, data=data)
        request.add_header(
            'ContentType', 'application/json; charset=UTF-8')

        response = urllib.request.urlopen(request)
        data = response.read()

        # 得到初始化用戶數據..
        res_fetch_msg_dict = json.loads(data.decode('utf-8'))

        print(res_fetch_msg_dict)
        self.write(data)

        # self.write('ok')



class TestHandler(tornado.web.RequestHandler):
    def get(self):

        self.write("Hello, world 1 ")
        time.sleep(10)
        self.write("Hello, world 2 ")
Handler
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
        body{
            margin: 0;
            padding: 0;
        }
        .login_alt{
            margin: 42px auto;
            text-align: center;
        }
        .image{
            display: block;
            width: 270px;
            height: 270px;
            margin: 42px auto;
        }
    </style>
</head>
<body>

    <div class="login_alt"><h1>二維碼登錄</h1></div>

    <img src="https://login.weixin.qq.com/qrcode/{{session_id}}" class="image">

    <script src="{{ static_url('js/jquery-2.1.4.min.js')}}" ></script>
    <script>
        $(function () {
            acquire_image();
        });
        function acquire_image() {
            $.ajax({
                url:'/login',
                type:'POST',
                success:function (data) {
                    if(data == '200'){
                        window.location.href = "/index";
                    }
                    else{
                        acquire_image();
                    }

                },
                error:function (data) {
                    console.log('error');
                }
            })
        }
    </script>
</body>
</html>
index.html
<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title></title>
    <style>
        .pg-header{
            height: 48px;
            background-color: #337ab7;
            color: white;
            line-height: 48px;
        }
        .container{}
        .menu{
            float: left;
            width: 250px;
            position: absolute;
            top:48px;
            bottom: 0;
            left: 0;
            overflow: auto;
            background-color: black;
            color: white;
        }
        .menu .item{
            padding: 10px 5px;
        }
        .menu .item:hover{
            background-color: #337ab7;
        }
        .content{
            float: left;
            position: absolute;
            left: 259px;
            top: 28px;
            right: 0;
            bottom: 0;
            overflow: auto;
        }
        .hide{
            display: none;
        }
        .chat-panel{
            position: relative;
        }
        .chat-panel .title{
            background-color: black;
            height: 50px;
            color: white;
        }
        .chat-panel .body{
            border: 1px solid black;
            height: 300px;
        }
        .chat-panel .footer{
            height: 200px;
        }

    </style>
</head>
<body style="margin: 0 auto;">
    <div class="pg-header">
        <span>登錄用戶:{{user['NickName']}}</span>
        <img class="hide" src="https://wx.qq.com{{user['HeadImgUrl']}}">
        <span class="hide">{{user['UserName']}}</span>
    </div>

    <div class="container">
        <div class="menu">
            {% for member in user_list_dict['MemberList'] %}
                <div class="item" user-name="{{member['UserName']}}" nick-name="{{member['NickName']}}">{{member['NickName']}}</div>
            {% end %}
        </div>
        <div class="content">
            <div class="chat-panel hide">
                <div class="title"></div>
                <div class="body"></div>
                <div class="footer">
                    <textarea id="message" class="msg"></textarea>
                    <input class="send" type="button" value="發送"  onclick="SendMsg();"/>
                    <input class="send" type="button" value="sync"  onclick="GetMsg();"/>
                </div>
            </div>

        </div>
    </div>
    <script src="{{ static_url('js/jquery-2.1.4.min.js')}}" ></script>
    <script>
        $(function(){
//            BindSendEvent();
            GetMsg();
            BindSendEvent2();
        });
//        USERNAME = "";
//        function BindSendEvent(){
//            $(".menu").delegate('.item', "dblclick", function(){
//                nickname = $(this).attr('nick-name');
//                USERNAME = $(this).attr('user-name');
//                $('.chat-panel .title').text(nickname);
//                $('.chat-panel').removeClass('hide');
//            })
//        }
        USERNAME = "";
        function BindSendEvent2() {
            $(".menu div").on('click',function () {
                USERNAME = $(this).attr('user-name');
                var nickname = $(this).attr('nick-name');
                $('.chat-panel').removeClass('hide');
                $('.chat-panel .title').text(nickname);
            })
        }

        function GetMsg(){
             $.ajax({
                url: "/msg",
                type: "GET",
                success: function (arg) {
                    GetMsg();
                }
            })
        }
        function SendMsg(){
            var sendMsg = $('#message').val();
            console.log({"username": window.USERNAME, "message": sendMsg});
            $.ajax({
                url: "/msg",
                data: {"username": window.USERNAME, "message": sendMsg},
                type: "POST",
                success: function (arg) {
                    console.log(arg);
                    $('#message').val("");
                }
            })
        }
    </script>
</body>
</html>
contact_list.html

相關文章
相關標籤/搜索