zoukankan      html  css  js  c++  java
  • 【Python之路】特别篇--微信Web网页版通信的全过程分析

      文章所使用Python版本为py3.5

    1.微信服务器返回一个会话ID

    微信Web版本不使用用户名和密码直接登录,而是采用二维码登录,所以服务器需要首先分配一个唯一的会话ID,用来标识当前的一次登录。

    通过查看网络请求我们找到了这个 二维码图片代表的随机字符串,(IcelandB9Entig==),

    2.通过会话ID获得二维码

    然后找到该随机字符串的来源请求

    请求方式为 GET形式 , 具体连接为:

    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('
    --------------------')
            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端登录

    当我们还没进行扫码登录时,发现微信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('
    --------------------')
            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

  • 相关阅读:
    大胆决定+细致用功, 才可能改变命运
    采用用同步编程的方式实现跨进程异步获取数据
    关于DataGridViewComboBoxCell修改后提交数据源
    学习:如何具有坚韧的性格
    汉语-成语:坚韧不拔
    汉语-词语:坚韧
    阿里云-OSS-Help-SKD参考-.NET:前言
    阿里云-OSS-OSS管理控制台:Bucket列表
    阿里云-OSS-OSS管理控制台:概览
    汉语-词语:推理
  • 原文地址:https://www.cnblogs.com/5poi/p/6725311.html
Copyright © 2011-2022 走看看