• web微信开发


    群里接收消息时,使用广播,但需要刷新页面才能接收到广播内容。
    
    - 轮询:  定时每秒刷新一次,当群不活跃时,群里的每个客户端都在刷新,对服务端压力太大。
    
    - 长轮询:客户端连服务端,服务端一直不断开,也不回消息。夯住请求(Web微信,WebQQ),
    		  假设夯住60s,60s后统一断开,然后客户端和服务端连接失败。然后紧接着再发送一次请求。相当于每分钟发送一次请求。
    		  夯住不动只要有一个人发送消息,立刻断开带着新信息返回。只要消息来了就返回断开,这样就实时接收消息。
    
    		- 无消息,超时之后断开,客户端立即发送请求;
    		- 有消息,立即返回
    		
    轮询和长轮询利用的是http协议,这种请求是单向的,目前长轮询使用广泛。
    
    - WebSocket
    	相比轮询和长轮询更好,客户端和服务端不断开,客户端和服务端可以相互接收消息。但是不是所有的浏览器都支持。目前还未大批量使用,以后是趋势。
    
    
    1. 显示二维码
    	打开微信网页微信二维码登录时,未扫码登录时二维码登录页面和微信服务端一直在长轮询状态。
    	当手机扫码时,手机向微信服务端发送请求,直接拿到结果给微信网页端,页面登录状态改变。
    	二维码本质是图片,每次刷新页面图片都不同,每次后缀都不同。
    	向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&_=1504151392313(其中1504151392313是时间戳)
    	发送请求获取响应window.QRLogin.code = 200; window.QRLogin.uuid = "wdLetLlNoQ==",二维码随机字符串uuid:"wdLetLlNoQ==",根据uuid创建二维码。
    	src="https://login.weixin.qq.com/qrcode/wdLetLlNoQ=="
    	src="https://login.weixin.qq.com/qrcode/YeOkCQK4FQ=="
     
     
    	- 获取uuid
    	- 根据uuid创建二维码
    	
    
    
    发送消息:
    	post_data = {
    		"BaseRequest": {
    			'xxx': 123123123123,
    			form
    			to
    			msg: 中文
    			'xxx': 123123123123,
    		}
    	}
    	# requests.post(json=post_data,headers={'cotnen':'json'})
    	# requests.post(data=json.dumps(post_data),headers={'cotnen':'json'})
    	
    	# requests.post(data=json.dumps(post_data,ensure_ascii=False),headers={'cotnen':'json'})
    

    开发web微信

    - 打开wechat, 查看登录页面,猜想: 手机、web、微信服务器
    
    - 二维码
    
    - 扫码
    
    - 确定登录
    	- 登录cookie
    	200,
    	redirict_url: ticket
    	- 凭证cookie
    	
    	- 初始化: 最近信息
    
    
    - 显示头像
    	因为跨域头像无法显示显示:
    		我们的自己写的网站 http://127.0.0.1:
    		浏览器上保存这个网站http://127.0.0.1相关cookie 
    		访问我们自己的网站的图片时,携带我们自己的cookie	<img src='http://127.0.0.1' />
    		
    		自己写的网站访问微信的图片时,携带着我们网站的cookie,这就跨域了,不能带着我们本地的cookie去。 <img src='http://wx.qq.com.....' />
    			<img src='http://wx.qq.com.....' /> GET请求,get请求没有请求体,只有请求头
    			请求头:url: http://wx.qq.com.....
    					cookie: xxxx,							# 没有微信的cookie
    					referer: http://127.0.0.1... ****		# 因为是自己写的网站访问微信图片,referer默认当着当前url,微信可以通过referer阻拦访问,同样cookie也可以阻止访问
    					
    		
    	所以不直接向微信发消息获取头像,上面是浏览器发的消息,没法伪造请求头请求体cookie。可以向我们后台自己发,因为python的requests模块可以伪造这些信息。	
    		
    	<img src='http://127.0.0.1/img' />
    		v= requests.get(...,cookie,headers)
    	python的requests模块通过获取cookie,请求体信息。获取微信头像数据信息,然后再访问本地信息从而显示头像。
    
    
    - 显示所有联系人
    	...
    
    
    - 发消息
    	current_user = req.session['INIT_DICT']['User']['UserName'] # session初始化,User.UserName
    	to = req.POST.get('to') # @dfb23e0da382f51746575a038323834a
    	msg = req.POST.get('msg')# asdfasdfasdf
    
    	# session Ticket
    	# session Cookie
    	ticket_dict = req.session['TICKED_DICT']
    	ctime = int(time.time()*1000)
    
    	post_data = {
    		"BaseRequest":{
    			"DeviceID": "e384757757885382",
    			'Sid': ticket_dict['wxsid'],
    			'Uin': ticket_dict['wxuin'],
    			'Skey': ticket_dict['skey'],
    		},
    		"Msg":{
    			"ClientMsgId":ctime,
    				"LocalID":ctime,
    			"FromUserName": current_user,
    			"ToUserName":to,
    			"Content": msg,
    			"Type": 1
    		},
    		"Scene": 0
    	}
    
    	url = "https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxsendmsg?pass_ticket={0}".format(ticket_dict['pass_ticket'])
    	# res = requests.post(url=url,json=post_data) # application/json,json.dumps(post_data)
    	# res = requests.post(url=url,data=json.dumps(post_data),headers={'Content-Type': "application/json"}) # application/json,json.dumps(post_data)
    
    	res = requests.post(url=url,data=json.dumps(post_data,ensure_ascii=False).encode('utf-8'),headers={'Content-Type': "application/json"}) # application/json,json.dumps(post_data)
    	print(res.text)
    
    
    - 收消息
    	见代码
    

    总结: 

    a. 分析Http请求
    	- 请求方式
    	- URL
    	- 浏览器看到数据的二种形式
    		Form Data? 			# form表单数据类型,request.post中取
    			{
    				k: 1,
    				k: “fds”,
    				k: [11,2,3,4],	
    				k: {K:},		# 不能传字典,传字典只能把字典的key传到后台,发字典的时候需要转为字符串类型
    			}
    		request payload?		# json数据类型,整个数据当成字符串发到后台。request.body中取
    			{
    				k: 1,
    				k: “fds”,
    				k: [11,2,3,4],	
    				k: {K:},
    			}
    		
    		requests.post()
    	- 请求头:(爬网站进不去时,下面五个设置注意下,大部分可以爬取了)			
    		user-agent: 当前用户使用的设备,知乎爬虫需要带user-agent。
    		Referer: "xxx"
    		content-type: application/json,
    		host
    
    		cookie关键,cookie依附在请求头中
    		
    b. 代理
    	封IP时,代理设置
    

      

    具体代码如下:

    urlpatterns = [
        url(r'^admin/', admin.site.urls),
        url(r'^login.html$', views.login),
        url(r'^check_login.html$', views.check_login),
        url(r'^index.html$', views.index),
        url(r'^avatar.html$', views.avatar),
        url(r'^contact_list.html$', views.contact_list),
        url(r'^send_msg.html$', views.send_msg),
        url(r'^get_msg.html$', views.get_msg),
    ]
    urls.py
    from django.shortcuts import render,HttpResponse
    import requests
    import time
    import re
    import json
    
    def ticket(html):
        from bs4 import BeautifulSoup
        ret = {}
        soup = BeautifulSoup(html,'html.parser')
        for tag in soup.find(name='error').find_all():
            ret[tag.name] = tag.text
        return ret
    
    
    def login(req):
        if req.method == 'GET':
            uuid_time = int(time.time() * 1000)
    
            base_uuid_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}"
            uuid_url =base_uuid_url.format(uuid_time)
            r1 = requests.get(uuid_url)
            result = re.findall('= "(.*)";',r1.text)
            uuid = result[0]
    
            req.session['UUID_TIME'] = uuid_time
            req.session['UUID'] = uuid
    
            return render(req,'login.html',{'uuid':uuid})
    def check_login(req):
        response = {'code': 408,'data':None}
    
        ctime = int(time.time()*1000)
        # base_login_url = "https://login.wx.qq.com/cgi-bin/mmwebwx-bin/login?loginicon=true&uuid={0}&tip=0&r=-735595472&_={1}"
        base_login_url = "https://login.wx.qq.com/cgi-bin/mmwebwx-bin/login?loginicon=true&uuid={0}&tip=0&r=-735595472&_={1}"
        # "https://login.wx.qq.com/cgi-bin/mmwebwx-bin/login?loginicon=true&uuid=AbPhQTMl9w==&tip=0&r=-736896961&_=1503975440649"
        login_url = base_login_url.format(req.session['UUID'],ctime)
        r1 = requests.get(login_url)
        if 'window.code=408' in r1.text:
            # 无人扫码
            response['code'] = 408
        elif 'window.code=201' in r1.text:
            # 扫码,返回头像
            response['code'] = 201
            response['data'] = re.findall("window.userAvatar = '(.*)';",r1.text)[0]
        elif 'window.code=200' in r1.text:
            # 扫码,并确认登录
            req.session['LOGIN_COOKIE'] = r1.cookies.get_dict()
            base_redirect_url = re.findall('redirect_uri="(.*)";',r1.text)[0]
            redirect_url = base_redirect_url + '&fun=new&version=v2'
    
            # 获取凭证
            r2 = requests.get(redirect_url)
            ticket_dict = ticket(r2.text)
            req.session['TICKED_DICT'] = ticket_dict
            req.session['TICKED_COOKIE'] = r2.cookies.get_dict()
    
    
            # 初始化,获取最近联系人信息:工作号
            post_data = {
                "BaseRequest":{
                    "DeviceID": "e384757757885382",
                    'Sid': ticket_dict['wxsid'],
                    'Uin': ticket_dict['wxuin'],
                    'Skey': ticket_dict['skey'],
                }
            }
            print('初始化开始...')
            # 用户初始化,讲最近联系人个人信息放在session中
            init_url = "https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxinit?r=-740036701&pass_ticket={0}".format(ticket_dict['pass_ticket'])
            r3 = requests.post(
                url=init_url,
                json=post_data
            )
            r3.encoding = 'utf-8'
            init_dict = json.loads(r3.text)
            req.session['INIT_DICT'] = init_dict
            response['code'] = 200
    
        return HttpResponse(json.dumps(response))
    
    
    def avatar(req):
        prev = req.GET.get('prev') # /cgi-bin/mmwebwx-bin/webwxgeticon?seq=602427528
        username = req.GET.get('username') # @fb736164312cbcdb9abe746d81e24835
        skey = req.GET.get('skey') # @crypt_2ccf8ab9_4414c9f723cbe6e9caca48b7deceff93
        img_url = "https://wx.qq.com{0}&username={1}&skey={2}".format(prev,username,skey)
    
        cookies= {}
        cookies.update(req.session['LOGIN_COOKIE'])
        cookies.update(req.session['TICKED_COOKIE'])
        print(img_url)
        res = requests.get(img_url,cookies=cookies,headers={'Content-Type': 'image/jpeg'})
        return HttpResponse(res.content)
    
    def index(req):
        """显示最近联系人"""
        # https://wx.qq.com
        return render(req,'index.html')
    
    
    def contact_list(req):
        """
        获取所有联系人
        :param req:
        :return:
        """
        ctime = int(time.time()*1000)
        base_url = "https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxgetcontact?lang=zh_CN&r={0}&seq=0&skey={1}"
        url = base_url.format(ctime,req.session['TICKED_DICT']['skey'])
        cookies = {}
        cookies.update(req.session['LOGIN_COOKIE'])
        cookies.update(req.session['TICKED_COOKIE'])
    
        r1 = requests.get(url,cookies=cookies)
        r1.encoding = 'utf-8'
    
        user_list = json.loads(r1.text)
    
        return render(req, 'contact_list.html',{'user_list':user_list})
    
    
    def send_msg(req):
        """
        发送消息
        :param req:
        :return:
        """
        current_user = req.session['INIT_DICT']['User']['UserName'] # session初始化,User.UserName
        to = req.POST.get('to') # @dfb23e0da382f51746575a038323834a
        msg = req.POST.get('msg')# asdfasdfasdf
    
        # session Ticket
        # session Cookie
        ticket_dict = req.session['TICKED_DICT']
        ctime = int(time.time()*1000)
    
        post_data = {
            "BaseRequest":{
                "DeviceID": "e384757757885382",
                'Sid': ticket_dict['wxsid'],
                'Uin': ticket_dict['wxuin'],
                'Skey': ticket_dict['skey'],
            },
            "Msg":{
                "ClientMsgId":ctime,
                    "LocalID":ctime,
                "FromUserName": current_user,
                "ToUserName":to,
                "Content": msg,
                "Type": 1
            },
            "Scene": 0
        }
    
        url = "https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxsendmsg?pass_ticket={0}".format(ticket_dict['pass_ticket'])
        # res = requests.post(url=url,json=post_data) # application/json,json.dumps(post_data)
        # res = requests.post(url=url,data=json.dumps(post_data),headers={'Content-Type': "application/json"}) # application/json,json.dumps(post_data)
    
        res = requests.post(url=url,data=json.dumps(post_data,ensure_ascii=False).encode('utf-8'),headers={'Content-Type': "application/json"}) # application/json,json.dumps(post_data)
        print(res.text)
        return HttpResponse('...')
    
    
    
    def get_msg(req):
        """
        长轮询获取消息
        :param req:
        :return:
        """
        # 检查是否有消息到来
        ctime = int(time.time()*1000)
        ticket_dict = req.session['TICKED_DICT']
        check_msg_url = "https://webpush.wx.qq.com/cgi-bin/mmwebwx-bin/synccheck"
    
        cookies = {}
        cookies.update(req.session['LOGIN_COOKIE'])
        cookies.update(req.session['TICKED_COOKIE'])
    
    
    
        synckey_dict = req.session['INIT_DICT']['SyncKey']
        synckey_list = []
        for item in synckey_dict['List']:
            tmp = "%s_%s" %(item['Key'],item['Val'])
            synckey_list.append(tmp)
        synckey = "|".join(synckey_list)
    
    
        r1 = requests.get(
            url=check_msg_url,
            params={
                'r': ctime,
                "deviceid": "e384757757885382",
                'sid': ticket_dict['wxsid'],
                'uin': ticket_dict['wxuin'],
                'skey': ticket_dict['skey'],
                '_': ctime,
                'synckey': synckey
            },
            cookies=cookies
        )
        print(r1.text)
        if '{retcode:"0",selector:"0"}' in r1.text:
            return HttpResponse('...')
    
        # 有消息,获取消息
        base_get_msg_url = "https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxsync?sid={0}&skey={1}&lang=zh_CN&pass_ticket={2}"
        get_msg_url = base_get_msg_url.format(ticket_dict['wxsid'],ticket_dict['skey'],ticket_dict['pass_ticket'])
    
        post_data = {
            "BaseRequest":{
                    "DeviceID": "e384757757885382",
                    'Sid': ticket_dict['wxsid'],
                    'Uin': ticket_dict['wxuin'],
                    'Skey': ticket_dict['skey'],
                },
            'SyncKey': req.session['INIT_DICT']['SyncKey']
        }
        r2 = requests.post(
            url = get_msg_url,
            json=post_data,
            cookies=cookies
        )
        r2.encoding = 'utf-8'
        # 接受到消息: 消息,synckey
        msg_dict = json.loads(r2.text)
        print(msg_dict)
        for msg in msg_dict['AddMsgList']:
            print('您有新消息到来:',msg['Content'])
        init_dict = req.session['INIT_DICT']
        init_dict['SyncKey'] =  msg_dict['SyncKey']
        req.session['INIT_DICT'] = init_dict
    
        return HttpResponse('...')
    views.py
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
        <div>
            <img style="height: 400px; 400px;" id="img" src="https://login.weixin.qq.com/qrcode/{{uuid}}">
        </div>
    
        <script src="/static/jquery-1.12.4.js"></script>
    
        <script>
            
            $(function () {
                checkLogin();
            });
            
            function checkLogin() {
                $.ajax({
                    url: '/check_login.html',
                    type: 'get',
                    data: {},
                    dataType: 'JSON',
                    success:function (arg) {
                        if(arg.code == 408){
                            checkLogin();
                        }else if(arg.code == 201){
                            $('#img').attr('src',arg.data);
                            checkLogin();
                        }else {
                            location.href = "/index.html"
                        }
    
                    }
                })
            }
        </script>
    </body>
    </html>
    login.html
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
        <h1>个人信息</h1>
        <img src="/avatar.html?prev={{ request.session.INIT_DICT.User.HeadImgUrl }}">
        <h2>{{ request.session.INIT_DICT.User.NickName }}</h2>
        <h1>最近联系人</h1>
            <ul>
            {% for user in  request.session.INIT_DICT.ContactList %}
                <li><img src="/avatar.html?prev={{ user.HeadImgUrl }}">  {{ user.UserName }}   {{ user.NickName }}</li>
            {% endfor %}
            </ul>
    
            <a href="/contact_list.html">更多联系人</a>
        <h1>公众号信息</h1>
    </body>
    </html>
    index
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
        <h1>发送消息</h1>
            <input placeholder="接受者" id="to" />
            <input placeholder="消息内容" id="msg" />
            <input type="button" value="发送" onclick="sendMsg();" />
        <h1>用户列表({{ user_list.MemberCount }})</h1>
        {% for user in user_list.MemberList %}
            <div username="{{ user.UserName }}">
    {#            <img style=" 50px;height: 50px;" src="/avatar.html?prev={{ user.HeadImgUrl }}"><span>{{ user.NickName }}</span>#}
                <span>{{ user.NickName }}</span>
            </div>
        {% endfor %}
        <script src="/static/jquery-1.12.4.js"></script>
        <script>
            $(function () {
                getMsg();
            });
    
            function getMsg() {
                $.ajax({
                    url: '/get_msg.html',
                    type: 'GET',
                    success:function (arg) {
                        //console.log(arg);
                        getMsg();
                    }
                })
            }
    
    
            function  sendMsg() {
                $.ajax({
                    url: '/send_msg.html',
                    type: "POST",
                    data: {'to': $('#to').val(), 'msg': $('#msg').val()},
                    success:function (arg) {
                        alert(arg);
                    }
                })
            }
        </script>
    </body>
    </html>
    contact_list.html
  • 相关阅读:
    [C/C++] 结构体内存对齐用法
    [其他] 关于C语言中使用未声明函数的问题
    [其他] 项目中的一个小问题
    【C++】DLL内共享数据区在进程间共享数据(重要)
    [MFC] CString小用例
    [C++] 频谱图中 FFT快速傅里叶变换C++实现
    [MFC] TabControl选项卡的使用
    [MFC] CFile读写文件实现(高效)
    [MFC] 编辑框 EditControl 输入数字范围限制
    [MFC] 对话框菜单项Menu选中打勾(单选,多选)
  • 原文地址:https://www.cnblogs.com/xuyaping/p/7754951.html
Copyright © 2020-2023  润新知