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


前言:

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

  a、實現返回二維碼

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

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

  d、實現顯示所有的聯系人

  e、實現發送消息

  

  下面我們就開始實現上述的功能,在看這篇博客的之前,讀者朋友需要去了解一下長輪詢的知識,因為wei微信的登陸就用到了長輪詢,首先我們先把web登陸的流程梳理一下,然后在實現我們的功能

 

一、web微信登陸分析

1、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,然后取整,生成的方法如下

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

  

b、分析這個url的返回值

 

c、查看網頁的源代碼,看下這個二維碼到底是什么

 

看下img標簽的src屬性,有沒有注意到,src的這一段字符串oaKKJgJRhA==,是我們返回二維碼的url返回的字符串,所以我們就可以拼接出來二維碼這個圖片的src的地址

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

  

 

2、等待用戶掃碼

 

這里就用到了一個長輪詢,如果客戶一直沒有掃碼,則會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,則表示等待用戶掃碼

3、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,則證明用戶已經掃碼成功

 

4、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,則證明登陸成功

 

5、分析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后,方便的后面的請求使用

 

6、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頁面就可以了

 

7、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、這次請求的返回信息就是所有的聯系人

 

8、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

 

二、我們的代碼實現

通過上面的分析,我相信大家對web微信的請求已經非常了解了,下面我們使用requests+bs4+djangon來實現一個建議的web微信

1、首先看下登陸的html,重點看下我的注釋

 

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

 

 3、然后后看下等待用戶掃碼的后台邏輯

 

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

 

 5、在來看下用戶掃碼后的后台邏輯

 

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

 

 7、在看下后端處理用戶點擊登陸的邏輯

 

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

 

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

 

 10、在看下index.html這個頁面,這個數據結構比較簡單,大家自己自己抓包看

 

 11、我們再看下查所有人聯系人

 

 12、看下對應的視圖函數,拼接url,然后把返回值返回給前端

 

 13、前端渲染數據即可

 

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

 

15、再看下后端的處理邏輯,主要是拼接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、方式1,處理不了中文,由於json的問題
            # json=data_dict

            # 2、方式2,解決了json處理不了中文的問題,但是微信用的解碼是不是常見的解碼方式,所以還是處理不了中文
            # data = json.dumps(
            #     data_dict,
            #     ensure_ascii=False
            # )

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

        return HttpResponse("success")

  

 三、整體的后端代碼

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、方式1,處理不了中文,由於json的問題
            # json=data_dict

            # 2、方式2,解決了json處理不了中文的問題,但是微信用的解碼是不是常見的解碼方式,所以還是處理不了中文
            # data = json.dumps(
            #     data_dict,
            #     ensure_ascii=False
            # )

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

        return HttpResponse("success")

  

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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM