requests+django+bs4實現一個web微信的功能

前言:html

  今天咱們利用requests模塊+django+bs4瀏覽器來實現一個web微信的基本功能,主要實現的功能以下前端

  a、實現返回二維碼python

  b、實現手機掃碼後二維碼變成變成頭像web

  c、實現手機點擊登錄成功顯示微信的最近聯繫人django

  d、實現顯示全部的聯繫人json

  e、實現發送消息後端

  

  下面咱們就開始實現上述的功能,在看這篇博客的以前,讀者朋友須要去了解一下長輪詢的知識,由於wei微信的登錄就用到了長輪詢,首先咱們先把web登錄的流程梳理一下,而後在實現咱們的功能瀏覽器

 

1、web微信登錄分析

一、web微信二維碼分析

 

 a、首先拿到url,這個請求是get請求微信

https://login.wx2.qq.com/jslogin?appid=wx782c26e4c19acffb&redirect_uri=https://wx2.qq.com/cgi-bin/mmwebwx-bin/webwxnewloginpage&fun=new&lang=zh_&_=1555510256420

  

這個url很好構建,只有1555510256420這個參數須要咱們認爲生成,其餘他就是時間戳*1000,而後取整,生成的方法以下cookie

t = int(time.time() * 1000)

  

b、分析這個url的返回值

 

c、查看網頁的源代碼,看下這個二維碼究竟是什麼

 

看下img標籤的src屬性,有沒有注意到,src的這一段字符串oaKKJgJRhA==,是咱們返回二維碼的url返回的字符串,因此咱們就能夠拼接出來二維碼這個圖片的src的地址

https://login.weixin.qq.com/qrcode/oaKKJgJRhA==  

  

 

二、等待用戶掃碼

 

這裏就用到了一個長輪詢,若是客戶一直沒有掃碼,則會hang住,等待客戶的掃碼

a、先來分析一下url

https://login.wx2.qq.com/cgi-bin/mmwebwx-bin/login?loginicon=true&uuid=oeoQNe1EiA==&tip=1&r=-732967182&_=1555511127069

 

這個url有2個地方須要咱們來構建

 

 第一個參數就上一步返回的字符串,第二個參數就是一個仍是一個時間戳

b、在來看下這個url返回了什麼

 

 只有一個狀態碼408

 結論:若是url的返回的code爲408,則表示等待用戶掃碼

三、web微信顯示頭像分析

手機掃碼後,二維碼變成頭像

 

a、先來分析url

https://login.wx2.qq.com/cgi-bin/mmwebwx-bin/login?loginicon=true&uuid=Qfn4ldhuNQ==&tip=1&r=-732688468&_=1555510848123

  

這個url和上面的url同樣,因此咱們知道,第一步返回的字符串很是重要,因此咱們要把這段字符串放在session中

b、在來看下url的返回值

 

這裏返回了一段字符串,code爲201,後面那一段字符串是頭像的地址

 

 c、咱們在來看下html中的img標籤的src的地址

 

 

 結論:返回201,則證實用戶已經掃碼成功

 

四、web微信登錄分析

 

a、首先url仍是以前的url,這裏就不作分析

https://login.wx2.qq.com/cgi-bin/mmwebwx-bin/login?loginicon=true&uuid=YacjFJrAfA==&tip=0&r=-733737113&_=1555511755717

  

b、看下此次請求的返回值

這裏有一個跳轉的url,也就是當咱們點擊登錄後,會跳轉到這個url

這裏還有一個返回碼是200

 

結論:狀態碼返回200,則證實登錄成功

 

五、分析web微信的跳轉url

 

a、分析一下此次請求的返回值

<error><ret>0</ret><message></message><skey>@crypt_90b16895_59f7cbfc1c217310b90558af662ea9c7</skey><wxsid>VP1xxDiAiU5Xz8gN</wxsid><wxuin>1632086000</wxuin><pass_ticket>w%2BIW73Y3XXFLqfA%2BBworrfgKu5aRlyXW%2F57wtMPYwrP%2BWnDW3ieWQ8jBmUUTbawy</pass_ticket><isgrayscale>1</isgrayscale></error>

  

這個返回值很是重要,咱們後面登錄後須要作的操做都須要這裏的信息。因此這個信息咱們也要組合一下放在session後,方便的後面的請求使用

 

六、web微信顯示最近聯繫人流程分析

訪問爲跳轉url後,拿到返回值信息,web微信又會發送一個post請求,獲取最近聯繫人信息

 

 a、先看下url,這裏url就須要用到上面跳轉url的返回值的信息來拼接

 

https://wx2.qq.com/cgi-bin/mmwebwx-bin/webwxinit?r=-733594626&pass_ticket=w%2BIW73Y3XXFLqfA%2BBworrfgKu5aRlyXW%2F57wtMPYwrP%2BWnDW3ieWQ8jBmUUTbawy

  

 b、這個請求的返回值就是最近聯繫人

 

 c、咱們就能夠把這些數據渲染到html頁面就能夠了

 

七、web微信顯示所有聯繫人

 

 點擊這裏,就會顯示所有聯繫人

a、分析一下url

https://wx2.qq.com/cgi-bin/mmwebwx-bin/webwxgetcontact?pass_ticket=w%2BIW73Y3XXFLqfA%2BBworrfgKu5aRlyXW%2F57wtMPYwrP%2BWnDW3ieWQ8jBmUUTbawy&r=1555511910553&seq=0&skey=@crypt_90b16895_59f7cbfc1c217310b90558af662ea9c7

  

咱們徹底能夠根據session中的數據拼接這個字符串

b、此次請求的返回信息就是全部的聯繫人

 

八、web發送消息

 

 發送消息是一個post的請求

 a、先來分析url

https://wx2.qq.com/cgi-bin/mmwebwx-bin/webwxsendmsg?pass_ticket=w%2BIW73Y3XXFLqfA%2BBworrfgKu5aRlyXW%2F57wtMPYwrP%2BWnDW3ieWQ8jBmUUTbawy

  

咱們能夠經過session中的數據拼接出這個url

 

b、在來看下此次post攜帶的請求體,咱們徹底能夠經過session中的數據拼接出這個請求體

 

 c、分析msg這個信息

第一條是時間戳

第二條是發送的內容

第三條發送者的微信id

第四條也是時間戳

第五條是接受者的微信id

 

2、咱們的代碼實現

經過上面的分析,我相信你們對web微信的請求已經很是瞭解了,下面咱們使用requests+bs4+djangon來實現一個建議的web微信

一、首先看下登錄的html,重點看下個人註釋

 

 二、進入views文件,看下返回二維碼的視圖函數,咱們注意到,前面的html須要q_code這個變量來渲染img標籤的src的路徑,顯示二維碼

 

 三、而後後看下等待用戶掃碼的後臺邏輯

 

四、看下前端處理408返回碼的邏輯

 

 五、在來看下用戶掃碼後的後臺邏輯

 

 六、在看下前端收到201的返回值處理邏輯,首先修改二維碼的地址爲頭像的地址,而後再次發送一次請求,等待用戶點擊確認

 

 七、在看下後端處理用戶點擊登錄的邏輯

 

 八、在看下前端處理200請求的邏輯,會跳轉到一個最近聯繫人的頁面

 

九、咱們在看下這個url對應的視圖函數,這個視圖函數是返回最近聯繫人的函數,須要攜帶規定的請求體,這些請求體已經被存儲到session中

 

 十、在看下index.html這個頁面,這個數據結構比較簡單,你們本身本身抓包看

 

 十一、咱們再看下查全部人聯繫人

 

 十二、看下對應的視圖函數,拼接url,而後把返回值返回給前端

 

 1三、前端渲染數據便可

 

 1四、在看發送信息的前端頁面

 

1五、再看下後端的處理邏輯,主要是拼接url和處理中文的信息

def sendmsg(request):
    if request.method == "GET":
        return render(request,"sendmsg.html")

    else:
        from_user = request.POST.get("from_user")
        to_user = request.POST.get("to_user")
        content = request.POST.get("content")

        data_dict = {
            "BaseRequest":{
                "DeviceID":"e461335461567419",
                "Sid":request.session["temp_dict"].get("wxsid"),
                "Skey":request.session["temp_dict"].get("skey"),
                "Uin":request.session["temp_dict"].get("wxuin")
            },
            "Msg":{
                "ClientMsgId":int(time.time() * 1000),
                "Content":content,
                "FromUserName":from_user,
                "LocalID":int(time.time() * 1000),
                "ToUserName":to_user,
                "Type":1
            },
        "Scene":0
        }
        rep = requests.post(
            url= "https://wx2.qq.com/cgi-bin/mmwebwx-bin/webwxsendmsg?lang=zh_CN&pass_ticket={p}".format(p = request.session["temp_dict"]["pass_ticket"]),

            # 一、方式1,處理不了中文,因爲json的問題
            # json=data_dict

            # 二、方式2,解決了json處理不了中文的問題,可是微信用的解碼是否是常見的解碼方式,因此仍是處理不了中文
            # data = json.dumps(
            #     data_dict,
            #     ensure_ascii=False
            # )

            # 三、方式3,直接發送二進制文件,就能夠解決發送中文的問題
            data = bytes(json.dumps(
                data_dict,
                ensure_ascii=False
            ),encoding="utf-8")
        )
        print(rep.text)

        return HttpResponse("success")

  

 3、總體的後端代碼

from django.shortcuts import render
from django.shortcuts import HttpResponse
from django.shortcuts import redirect
import requests
import re
# Create your views here.

import time
def login(request):
    if request.method.lower() == "get":
        t = int(time.time() * 1000)
        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&_={t}"
        res = requests.get(url=url)
        # window.QRLogin.code = 200;
        # window.QRLogin.uuid = "oc86pbX-hQ==";
        re_obj = re.compile('= "(.*==)";$')
        q_code = re_obj.findall(res.text)[0]
        request.session["q_code"] = q_code
        return render(request,"login.html",locals())

import json
import re
from bs4 import BeautifulSoup
# BeautifulSoup還能夠處理xml文檔
def checklogin(request):
    if request.method.lower() == "get":
        res_dict = {"code":408,"img":None,"url":None}
        code = request.session["q_code"]
        t = int(time.time() * 1000)
        url = "https://login.wx.qq.com/cgi-bin/mmwebwx-bin/login?loginicon=true&uuid={code}&tip=0&r=-131537270&_={t}".format(code = code,t = t)
        rep = requests.get(url=url)
        if "window.code=408;" in rep.text:
            return HttpResponse(json.dumps(res_dict))

        elif "window.code=201;" in rep.text:
            # 掃碼成功
            obj = re.compile("window.userAvatar = '(.*)';")
            src = obj.findall(rep.text)[0]
            res_dict["code"] = 201
            res_dict["img"] = src

            return HttpResponse(json.dumps(res_dict))
        elif "window.code=200;" in rep.text:
            # 肯定登錄
            obj = re.compile('window.redirect_uri="(.*)";')
            url = obj.findall(rep.text)[0]
            res_dict["code"] = 200
            res_dict["url"] = url
            new = requests.get(url = url + "&fun=new&version=v2&lang=zh_CN")
            script_obj = BeautifulSoup(new.text,"html.parser")
            temp_dict = {}
            for tag in script_obj.find(name="error"):
                temp_dict[tag.name] = tag.text

            request.session["temp_dict"] = temp_dict
            request.session["cookies"] = new.cookies.get_dict()
            return HttpResponse(json.dumps(res_dict))
        else:
            pass
            return HttpResponse("haha")


def index(request):
    url = "https://wx2.qq.com/cgi-bin/mmwebwx-bin/webwxinit?r=-221192329&pass_ticket={t}".format(t = request.session["temp_dict"].get("pass_ticket"))
    init = requests.post(
        url=url,
        json={
            "BaseRequest":{
                "DeviceID":"e701447882725714",
                "Sid":request.session["temp_dict"].get("wxsid"),
                "Skey":request.session["temp_dict"].get("skey"),
                "Uin":request.session["temp_dict"].get("wxuin")
            }
        }
    )
    init.encoding = "utf-8"
    init_user_dict = init.json()
    return render(request,"index.html",locals())


def contact(request):
    t = int(time.time() * 1000)
    rep = requests.get(
        url = "https://wx2.qq.com/cgi-bin/mmwebwx-bin/webwxgetcontact?lang=zh_CN&pass_ticket={p}&r={t}&seq=0&skey={s}".format(t = t,
                                                                                                                              p = request.session["temp_dict"]["pass_ticket"],
                                                                                                                              s = request.session["temp_dict"]["skey"]),
        cookies = request.session["cookies"]
    )
    rep.encoding = "utf-8"
    user_list= rep.json()

    return render(request,"contact.html",locals())


def avator(request):
    # print(request.GET.get("prev"))
    # print(request.GET.get("username"))
    # print(request.GET.get("skey"))
    url = "https://wx2.qq.com{p}&username={u}&skey={s}".format(p = request.GET.get("prev"),
                                                                   u = request.GET.get("username"),
                                                                   s = request.GET.get("skey")
                                                                   )
    img = requests.get(
        url = url,
        cookies = request.session["cookies"]
    )
    print(url)
    return img.content


def sendmsg(request):
    if request.method == "GET":
        return render(request,"sendmsg.html")

    else:
        from_user = request.POST.get("from_user")
        to_user = request.POST.get("to_user")
        content = request.POST.get("content")

        data_dict = {
            "BaseRequest":{
                "DeviceID":"e461335461567419",
                "Sid":request.session["temp_dict"].get("wxsid"),
                "Skey":request.session["temp_dict"].get("skey"),
                "Uin":request.session["temp_dict"].get("wxuin")
            },
            "Msg":{
                "ClientMsgId":int(time.time() * 1000),
                "Content":content,
                "FromUserName":from_user,
                "LocalID":int(time.time() * 1000),
                "ToUserName":to_user,
                "Type":1
            },
        "Scene":0
        }
        rep = requests.post(
            url= "https://wx2.qq.com/cgi-bin/mmwebwx-bin/webwxsendmsg?lang=zh_CN&pass_ticket={p}".format(p = request.session["temp_dict"]["pass_ticket"]),

            # 一、方式1,處理不了中文,因爲json的問題
            # json=data_dict

            # 二、方式2,解決了json處理不了中文的問題,可是微信用的解碼是否是常見的解碼方式,因此仍是處理不了中文
            # data = json.dumps(
            #     data_dict,
            #     ensure_ascii=False
            # )

            # 三、方式3,直接發送二進制文件,就能夠解決發送中文的問題
            data = bytes(json.dumps(
                data_dict,
                ensure_ascii=False
            ),encoding="utf-8")
        )
        print(rep.text)

        return HttpResponse("success")

  

 相信若是你們看懂我前面分析web微信的邏輯,看懂應該不成問題。若是有不清楚的,請評論留言,感謝你們關注,謝謝!

相關文章
相關標籤/搜索