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微信html

- 打開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)


- 收消息
	見代碼

總結: python

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時,代理設置

  

具體代碼以下:jquery

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;width: 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="width: 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
相關文章
相關標籤/搜索