前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >如果使用 Python3(Flask)

如果使用 Python3(Flask)

作者头像
py3study
发布2020-01-06 14:36:22
4620
发布2020-01-06 14:36:22
举报
文章被收录于专栏:python3python3

[TOC]

一、获取登录的二维码

1.1、打开浏览器输入下面网址

代码语言:javascript
复制
https://wx.qq.com/

按下F12打开开发调试模式。

如果使用 Python3(Flask) 一步一步模拟一个网页微信客户端
如果使用 Python3(Flask) 一步一步模拟一个网页微信客户端
如果使用 Python3(Flask) 一步一步模拟一个网页微信客户端
如果使用 Python3(Flask) 一步一步模拟一个网页微信客户端

我们可以看到产生二维码的图片的URL为https://login.weixin.qq.com/qrcode/wbO9FUkKHg==,但是需要后面的一个参数wbO9FUkKHg==,这个随机码是怎么产生的呢,我们再继续寻找。

如果使用 Python3(Flask) 一步一步模拟一个网页微信客户端
如果使用 Python3(Flask) 一步一步模拟一个网页微信客户端

现在我们应该清楚了,浏览器先请求这个地址获取生成二维码的uuid,然后再把uuid传入之前的url生成二维码。

1.2、梳理原理

获取uuidURL代码如下,多次尝试发现最后一个数字是一直变动的,是时间戳:

代码语言:javascript
复制
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&_=1548209541594

生成二维码的URL如下,后面的参数就是上面URL产生的uuid

代码语言:javascript
复制
https://login.weixin.qq.com/qrcode/weE4D106jA==

1.3、代码实现

要实现这个功能,需要对 Python 的模块 Flask 有一些了解。 我们创建一个wechat.py,代码如下:

代码语言:javascript
复制
#!/usr/bin/python3.6
# -*- coding: UTF-8 -*-

# wangzan18@126.com
# 2018-10-16

from flask import Flask, render_template
import time
import requests
import re

app = Flask(__name__)

@app.route('/login', methods=['GET', 'POST'])
def login():
    """
    获取登录的二维码
    :return:
    """
    if request.method == 'GET':
        ctime = time.time() * 1000   # 模拟一个相同的时间戳
        base_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}'
        url = base_url.format(ctime)   # 字符串拼接,生成新的url
        response = requests.get(url)   # 向新的url发送get请求
        qcode = re.findall('uuid = "(.*)";', response.text)[0]   # 获取二维码的参数uuid
        return render_template('login.html', qcode=qcode)    # 把uuid传给前端模板
    else:
        pass

if __name__ == '__main__':
    app.run(debug=True, host="0.0.0.0")

因为要把参数传给前端模板,所以我们要创建模板文件,按照 Flask 的格式要求,我们在当前目录创建一个文件夹templates,在文件夹下面创建login.html,内容如下:

代码语言:javascript
复制
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Wechat_login</title>
</head>
<body>
   <div style="width: 300px;margin: 0 auto">
        <h1 style="text-align: center">微信登录</h1>
        <img id="img" style="height: 300px;width: 300px;" src="https://login.weixin.qq.com/qrcode/{{qcode}}" alt="">
   </div>
</body>
</html>

1.4、启动测试

现在我们启动微信,访问http://192.168.1.86:5000/login

如果使用 Python3(Flask) 一步一步模拟一个网页微信客户端
如果使用 Python3(Flask) 一步一步模拟一个网页微信客户端

每次刷新都是可以变更二维码的。

二、扫码成功

2.1、扫码状态

目前我们扫码之后页面没有任何变化,那到底是因为触发了页面的变化呢,我们继续来探究,我们看到生成二维码之后,浏览器一直请求某个地址,这个地址其实就是服务器返回我们的扫码状态。

如果使用 Python3(Flask) 一步一步模拟一个网页微信客户端
如果使用 Python3(Flask) 一步一步模拟一个网页微信客户端

开始请求一直处于pending状态,当在一定时间内(25s)探测不要用户扫码就中断,并给出一个返回值408,然后发起下一个探测。

如果使用 Python3(Flask) 一步一步模拟一个网页微信客户端
如果使用 Python3(Flask) 一步一步模拟一个网页微信客户端

通过我们测试下来,返回值主要有三种状态,如下

  • 用户为扫码:返回值为window.code=408
  • 用户扫码,没有点击登录:返回值为window.code=201;window.userAvatar = xxxx
  • 用户扫码,并点击登录:window.code=200;window.redirect_uri= xxxx

2.2、原理状态梳理

用户没有扫码,超时状态。

如果使用 Python3(Flask) 一步一步模拟一个网页微信客户端
如果使用 Python3(Flask) 一步一步模拟一个网页微信客户端

用户扫码,没有登录,返回一个用户头像的数据,并且立刻重新发起请求,探测用户是否点击确定。

如果使用 Python3(Flask) 一步一步模拟一个网页微信客户端
如果使用 Python3(Flask) 一步一步模拟一个网页微信客户端

扫码之后头像的数据如下:

如果使用 Python3(Flask) 一步一步模拟一个网页微信客户端
如果使用 Python3(Flask) 一步一步模拟一个网页微信客户端

2.3、代码实现

探测是否有用户扫码的url如下:

代码语言:javascript
复制
https://login.wx.qq.com/cgi-bin/mmwebwx-bin/login?loginicon=true&uuid=YagAJmDN2w==&tip=0&r=-2025309768&_=1548213510530

url里面主要的几个参数,如uuid,时间戳等我们都是可以通过前面获取到的,在之前的wechat.py增加一个函数check_login和对应的 api 接口来检查扫码状态:

代码语言:javascript
复制
#!/usr/bin/python3.6
# -*- coding: UTF-8 -*-

# wangzan18@126.com
# 2018-10-16

from flask import Flask, render_template, request, session, jsonify
import time
import requests
import re

app = Flask(__name__)
app.secret_key = 'wangzan18'

@app.route('/login', methods=['GET', 'POST'])
def login():
    """
    获取登录的二维码
    :return:
    """
    if request.method == 'GET':
        ctime = time.time() * 1000   # 模拟一个相同的时间戳
        base_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}'
        url = base_url.format(ctime)   # 字符串拼接,生成新的url
        response = requests.get(url)   # 向新的url发送get请求
        qcode = re.findall('uuid = "(.*)";', response.text)[0]   # 获取二维码的参数uuid
        session['qcode'] = qcode
        return render_template('login.html', qcode=qcode)    # 把uuid传给前端模板
    else:
        pass

@app.route('/check_login')
def check_login():
    """
    检查用户是否扫码登录
    :return:
    """
    response = {'code': 408}  # 默认用户没有扫码
    qcode = session.get('qcode')  # 获取用户前面获取的 uuid,用于放到下面的 url 里面
    ctime = time.time() * 1000
    check_url = "https://login.wx.qq.com/cgi-bin/mmwebwx-bin/login?loginicon=true&uuid={0}&tip=0&r=-1437802572&_={1}".format(qcode, ctime)
    ret = requests.get(check_url)  # 扫码返回值
    if 'code=201' in ret.text:
        # 扫码成功
        src = re.findall("userAvatar = '(.*)';", ret.text)[0]  # 获取扫码用户头像
        response['code'] = 201  # 获取扫码的返回值,放到字典response
        response['src'] = src  # 获取用户头像数据,放到字典response
    return jsonify(response)

if __name__ == '__main__':
    app.run(debug=True, host="0.0.0.0")

函数已经写好了,那函数怎么调用了,我们需要在login.html增加一段ajax代码,去请求调用我们api接口,login.html代码如下:

代码语言:javascript
复制
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Wechat_login</title>
</head>
<body>
   <div style="width: 300px;margin: 0 auto">
        <h1 style="text-align: center">微信登录</h1>
        <img id="img" style="height: 300px;width: 300px;" src="https://login.weixin.qq.com/qrcode/{{qcode}}" alt="">
   </div>

    <script src="/static/jquery-1.12.4.js"></script>
    <script>
        $(function () {
            checkLogin();
        })
        function checkLogin() {
            $.ajax({
                url:'/check_login',
                type:'GET',
                dataType:'JSON',
                success:function (arg) {
                    if(arg.code === 201){
                        // 扫码
                        $('#img').attr('src',arg.src);
                        checkLogin();
                    }else{
                        checkLogin();
                    }
                }
            })
        }
    </script>
</body>
</html>

我们在ajax代码中看到这里已经写了,用户扫码登录之后就跳转到index,目前这个我们还没有写,先不去验证。 注意代码里面我们使用到一个/static/jquery-1.12.4.js,这个是一个公共标准的 js 文件,大家可以去互联网获取。

2.4、扫码验证

我们同样打开我们的地址,并且打开F12调试按钮,然后进行一下扫码,看看如何变化。

如果使用 Python3(Flask) 一步一步模拟一个网页微信客户端
如果使用 Python3(Flask) 一步一步模拟一个网页微信客户端

我们可以看到,浏览器一直在进行探测登录状态,和官方的一样,那我们扫码查看一下。

如果使用 Python3(Flask) 一步一步模拟一个网页微信客户端
如果使用 Python3(Flask) 一步一步模拟一个网页微信客户端

我们可以看到,扫码之后自动获取了头像并且展示出来,因为我们还没有设定登录成功之后的 api,即使登录也不会有什么跳转。

三、确认登录

3.1、页面调试

我们继续打开官方的微信地址,并且打开调试模式,我们查看一下登录成功之后进行了哪些操作。

用户登录之后,会让我们重定向到一个新的地址获取初始化的一些参数。

如果使用 Python3(Flask) 一步一步模拟一个网页微信客户端
如果使用 Python3(Flask) 一步一步模拟一个网页微信客户端

跳转到新的地址之后,我们获取到一个 xml 结构的数据,这个数据是用来进行初始化需要的。 请求的地址为https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxnewloginpage?ticket=AXwgRhcMRSlLwikCn2I_PPn5@qrticket_0&uuid=gdH7PHqg4A==&lang=zh_CN&scan=1548214671&fun=new&version=v2&lang=zh_CN

如果使用 Python3(Flask) 一步一步模拟一个网页微信客户端
如果使用 Python3(Flask) 一步一步模拟一个网页微信客户端

进行初始化,初始化的 url 如下:

代码语言:javascript
复制
https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxinit?r=-2026305663&lang=zh_CN&pass_ticket=Ja8PaHs1heLZzSQihsRnNF%252Fu%252FzoHJQ%252BUHNV7u7N13K9iTJVaM70wfaINLcm4dqcF

这是一个POST请求,需要的参数正好是我们上面获取到的,如下图所示:

如果使用 Python3(Flask) 一步一步模拟一个网页微信客户端
如果使用 Python3(Flask) 一步一步模拟一个网页微信客户端

并且初始化之后返回用户通讯录的一些信息,如下:

如果使用 Python3(Flask) 一步一步模拟一个网页微信客户端
如果使用 Python3(Flask) 一步一步模拟一个网页微信客户端

3.2、代码实现

我们需要在函数check_login里面新增扫码成功之后的调整,以及跳转之后的页面indexwechat.py代码如下:

代码语言:javascript
复制
from flask import Flask, render_template, request, session, jsonify
import time
import requests
import re
from bs4 import BeautifulSoup

app = Flask(__name__)
app.secret_key = 'wangzan18'

def xml_parser(text):
    """
    格式化xml数据,修改成我们需要的格式
    :param text:
    :return:
    """
    dic = {}
    soup = BeautifulSoup(text, 'html.parser')
    div = soup.find(name='error')
    for item in div.find_all(recursive=False):
        dic[item.name] = item.text
    return dic

@app.route('/login', methods=['GET', 'POST'])
def login():
    """
    获取登录的二维码
    :return:
    """
    if request.method == 'GET':
        ctime = time.time() * 1000   # 模拟一个相同的时间戳
        base_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}'
        url = base_url.format(ctime)   # 字符串拼接,生成新的url
        response = requests.get(url)   # 向新的url发送get请求
        qcode = re.findall('uuid = "(.*)";', response.text)[0]  # 获取二维码的参数
        session['qcode'] = qcode
        return render_template('login.html', qcode=qcode)
    else:
        pass

@app.route('/check_login')
def check_login():
    """
    检查用户是否扫码登录
    :return:
    """
    response = {'code': 408}  # 默认用户没有扫码
    qcode = session.get('qcode')  # 获取用户前面获取的 uuid,用于放到下面的 url 里面
    ctime = time.time() * 1000
    check_url = "https://login.wx.qq.com/cgi-bin/mmwebwx-bin/login?loginicon=true&uuid={0}&tip=0&r=-1437802572&_={1}".format(qcode, ctime)
    ret = requests.get(check_url)  # 扫码返回值
    if 'code=201' in ret.text:
        # 扫码成功
        src = re.findall("userAvatar = '(.*)';", ret.text)[0]  # 获取扫码用户头像
        response['code'] = 201  # 获取扫码的返回值,放到字典response
        response['src'] = src  # 获取用户头像数据,放到字典response
    elif 'code=200' in ret.text:
        # 确认登录
        redirect_uri = re.findall('redirect_uri="(.*)";', ret.text)[0]   # 获取跳转的url

        # 向redirect_uri地址发送请求,获取凭证相关信息
        redirect_uri = redirect_uri + "&fun=new&version=v2&lang=zh_CN"
        ticket_ret = requests.get(redirect_uri)  # 获取xml参数
        ticket_dict = xml_parser(ticket_ret.text)  # 解析参数变成我们需要的格式
        session['ticket_dict'] = ticket_dict   # 或许我们初始化需要的ticket
        response['code'] = 200
    return jsonify(response)

@app.route('/index')
def index():
    ticket_dict = session.get('ticket_dict')  # 获取初始化需要的ticket
    init_url = "https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxinit?r=-1438401779&lang=zh_CN&pass_ticket={0}".format(
        ticket_dict.get('pass_ticket'))   # 调整好初始化的url
    data_dict = {
        "BaseRequest": {
               "Sid": ticket_dict.get('wxsid'),
               "Uin": ticket_dict.get('wxuin'),
               "Skey": ticket_dict.get('skey'),
           }
    }    # post需要的参数
    init_ret = requests.post(url=init_url, json=data_dict)  # 微信登录初始化
    init_ret.encoding = 'utf-8'
    user_dict = init_ret.json()  # 储存返回的json数据
    return render_template('index.html', user_dict=user_dict)  # 把返回的数据传给index.html

if __name__ == '__main__':
    app.run(debug=True, host="0.0.0.0")

然后我们需要在login.html里面添加登录成功之后跳转到接口/index,接口我们已经写好,完整代码如下:

代码语言:javascript
复制
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Wechat_login</title>
</head>
<body>
   <div style="width: 300px;margin: 0 auto">
        <h1 style="text-align: center">微信登录</h1>
        <img id="img" style="height: 300px;width: 300px;" src="https://login.weixin.qq.com/qrcode/{{qcode}}" alt="">
   </div>

    <script src="/static/jquery-1.12.4.js"></script>
    <script>
        $(function () {
            checkLogin();
        })
        function checkLogin() {
            $.ajax({
                url:'/check_login',
                type:'GET',
                dataType:'JSON',
                success:function (arg) {
                    if(arg.code === 201){
                        // 扫码
                        $('#img').attr('src',arg.src);
                        checkLogin();
                    }else if(arg.code === 200){
                        // 重定向到用户列表
                        location.href = '/index'
                    }else{
                        checkLogin();
                    }
                }
            })
        }
    </script>
</body>
</html>

用户登录成功之后调用接口/index,接口会把页面定向到index.html,其index.html完整代码如下:

代码语言:javascript
复制
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Wechat</title>
</head>
<body>
  <h1>欢迎登录:{{user_dict.User.NickName}}</h1>
    <h3>最近联系人</h3>
    <ul>
        {% for user in user_dict.ContactList%}
        <li>{{user.NickName}}</li>
        {% endfor %}
    </ul>
    <h3>微信订阅号</h3>
    <ul>
        {% for sub in user_dict.MPSubscribeMsgList %}
        {% for artlist in sub.MPArticleList %}
        <li>{{artlist.Title}}</li>
        {% endfor %}
        {% endfor %}
    </ul>
</body>
</html>

3.3、登录查看

我们点击确认登录之后,就跳转到我们的index.html页面,效果如下:

如果使用 Python3(Flask) 一步一步模拟一个网页微信客户端
如果使用 Python3(Flask) 一步一步模拟一个网页微信客户端
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2019-09-25 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、获取登录的二维码
    • 1.1、打开浏览器输入下面网址
      • 1.2、梳理原理
        • 1.3、代码实现
          • 1.4、启动测试
          • 二、扫码成功
            • 2.1、扫码状态
              • 2.2、原理状态梳理
                • 2.3、代码实现
                  • 2.4、扫码验证
                  • 三、确认登录
                    • 3.1、页面调试
                      • 3.2、代码实现
                        • 3.3、登录查看
                        领券
                        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档