网页微信协议分析(一)——登录

参考:https://www.52pojie.cn/thread-836149-1-1.html

1,先分析二维码,多次刷新页面对比,红色部分属于变动的参数

  二维码请求地址:https://login.weixin.qq.com/qrcode/wbHpeNosSQ==

2,接着倒推,找出是哪个请求返回的此参数wbHpeNosSQ==

GET:https://login.wx.qq.com/jslogin?appid=wx782c26e4c19acffb&redirect_uri=https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxnewloginpage&fun=new&lang=zh_CN&_=1544935484177

响应内容:window.QRLogin.code = 200; window.QRLogin.uuid = "wbHpeNosSQ==";

分析:

  请求方式:get 

  域名路由:https://login.wx.qq.com/jslogin

  参数:

    appid=wx782c26e4c19acffb(不需要管,直接带入)

    redirect_uri=https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxnewloginpage(不需要管,直接带入)

    fun=new&lang=zh_CN(不需要管,直接带入)

    _=1544935484177(当前时间戳)

 

 3,通过工具解析二维码,得到内容:https://login.weixin.qq.com/l/wbHpeNosSQ==

与二维码请求地址对比:https://login.weixin.qq.com/qrcode/wbHpeNosSQ==

也就是说当我们扫描二维码的时候,
用微信访问了https://login.weixin.qq.com/l/wbHpeNosSQ==这个地址


总结:

  首先浏览器访问:https://login.wx.qq.com/jslogin?appid=wx782c26e4c19acffb&redirect_uri=https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxnewloginpage&fun=new&lang=zh_CN&_=时间戳

  获取到uuid(二维码需要的参数)

  

  紧接着浏览器访问:https://login.weixin.qq.com/qrcode/uuid

  获取到二维码

  

  最后我们微信扫描二维码,访问了:https://login.weixin.qq.com/l/uuid

 

 4,继续分析,图中红色部分不停的向服务器获取二维码状态,返回window.code=408;(处于等待状态)

GET访问:https://login.wx.qq.com/cgi-bin/mmwebwx-bin/login?loginicon=true&uuid=wbHpeNosSQ==&tip=1&r=1249597736&_=1544938628299

返回:window.code=408

分析:

  请求方式:get

  域名路由:https://login.wx.qq.com/cgi-bin/mmwebwx-bin/login

  参数:

    loginicon=true(不需要管,直接带入)

    uuid=wbHpeNosSQ==(二维码重要参数)

    tip=1(不需要管,直接带入)

    r=1249597736(不需要管,直接带入)

    _=1544938628299(当前时间戳)

  window.code=408(服务器返回的数据,408代表二维码未失效,也未被扫描)

  window.code=400(二维码超时,已失效)

当我们用微信扫描二维码,并登陆返回内容

  window.code=200;(扫描成功,二维码已被登录)
  window.redirect_uri="https://wx2.qq.com/cgi-bin/mmwebwx-bin/webwxnewloginpage?ticket=A6MgV6Y2cFTdpnYpTFlIiWTB@qrticket_0&uuid=4cPXU7HERw==&lang=zh_CN&scan=1545024906";

  出现redirect_uri返回的url,就代表登陆成功了,下一步访问这个地址,来获取返回用户信息和最重要的cookies

https://wx2.qq.com/cgi-bin/mmwebwx-bin/webwxnewloginpage?ticket=A6MgV6Y2cFTdpnYpTFlIiWTB@qrticket_0&uuid=4cPXU7HERw==&lang=zh_CN&scan=1545024906

5,获取cookies

 当我们访问redirect_uri返回的url时,从下图可以看出此链接返回了cookies,不过要注意此处访问返回的状态码301(重定向),在写代码时一定要禁用自动跳转

而返回的响应体:

{'skey': '@crypt_9bf897a2_d38a192ab54ece589fd59590a82dbcb4', 'wxsid': '9ScRHvQW23TYyyq1', 'wxuin': '2494888724', 'pass_ticket': 'nRxq1M%2BpTOyOloS4bgKofSlqKeiOcatTPd6HVhbJiz8qkgTLwGpy2ji%2Fx0xlueJQ'}

得到的是一个xml格式的消息,其中<skey><wxsid><wxuin><pass_ticket>保存并记录下来,以便后续包调用。

附上python源码:

import requests
import time
import re
import qrcode_terminal
from lxml import etree
"""
需要下载的模块
pip3 install qrcode_terminal
pip3 install lxml
"""
headers = {
    'user-agent': "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:63.0) Gecko/20100101 Firefox/63.0",
    'Connection': 'keep-alive',
    'Upgrade-Insecure-Requests': '1',
    'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
    'Accept-Enocding': 'gzip, deflate, br',
    'Accept-Language': 'zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2',
}


class Login():
    def __init__(self):
        # 创建会话
        session = requests.session()
        # 设置响应头
        session.headers = headers
        self.session = session

    def run(self):
        # 第一步:发送请求,获取二维码关键参数
        url = "https://login.web.wechat.com/jslogin?appid=wx782c26e4c19acffb&redirect_uri=https://web.wechat.com/cgi-bin/mmwebwx-bin/webwxnewloginpage&fun=new&lang=zh_CN&_=%s" % int(
            time.time() * 1000)
        # 发送请求
        res_data = self.session.get(url)
        # 正则:提取uuid
        uuid = re.search(r'"(.*?==)', res_data.text).group(1)

        # 第二步:打印二维码
        url = "https://login.weixin.qq.com/l/%s" % uuid
        qrcode_terminal.draw(url)

        # 第三部等待用户连接
        url = "https://login.web.wechat.com/cgi-bin/mmwebwx-bin/login?loginicon=true&uuid=%s&tip=0&r=1765586131&_=%s" % (
            uuid, int(time.time() * 1000))

        while True:
            # 发送请求
            res_data = self.session.get(url)
            # 正则:提取code
            code = re.search("redirect_uri", res_data.text)

            if code is not None:
                if code.group() == "redirect_uri":
                    print("已确认登录!")
                    # 正则:提取redirect_uri
                    redirect_uri = re.search(""(.*)"", res_data.text).group(1)

                    # 请求,allow_redirects=False必须禁止重定向
                    res_data = self.session.get(redirect_uri, allow_redirects=False)

                    # 把返回的cookieJar转换为字典类型cookies
                    cookies = requests.utils.dict_from_cookiejar(res_data.cookies)

                    # etree库处理返回的xml文本,创建对象
                    html = etree.XML(res_data.text)
                    # 类似于正则,分割元素<skey>,<wxsid>,<wxuin>,<pass_ticket>
                    html = html.xpath("//*")

                    # 存入字典
                    para = {}
                    for i in html:
                        if i.text is not None:
                            para[i.tag] = i.text

                    # 保存cookies到本地
                    with open("cookies.ini", "w")as f:
                        f.write(str(cookies))

                    # 保存返回的内容到本地<skey><wxsid><wxuin><pass_ticket>
                    with open("para.txt", "w") as f:
                        f.write(str(para))

                    break

    def __del__(self):
        self.session.close()

if __name__ == '__main__':
    # 创建对象
    l = Login()
    # 登录
    l.run()
原文地址:https://www.cnblogs.com/sickle/p/10126246.html