<div class="qrcode" ng-class="{hide: isScan || isAssociationLogin || isBrokenNetwork}">
class="img" mm-error="qrcodeException()" ng-class="{'qrcode_expired': isNeedRefresh}" mm-src="https://login.weixin.qq.com/qrcode/Ie_lVu7qmQ==" mm-src-load="qrcodeLoad" mm-src-parallel="" mm-src-timeout="10" mm-src-retry-count="2" src="https://login.weixin.qq.com/qrcode/Ie_lVu7qmQ==">
<div ng-show="!isNeedRefresh" class="">
class="sub_title">使用手机微信扫码登录
class="sub_desc">网页版微信需要配合手机使用
div>
<div ng-show="isNeedRefresh" class="ng-hide">
<div class="refresh_qrcode_mask">
class="icon-refresh" ng-class="{rotateLoading: isRotateLoading}" ng-click="refreshQrcode()">
div>
class="refresh_tips">二维码失效,点击刷新
div>
div>
我们看下src="https://login.weixin.qq.com/qrcode/Ie_lVu7qmQ=="
图片式如何生成的呢?
由此我们得知web微信,在输出https://wx.qq.com/时候,会发起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&_=1525767248719
请求,返回window.QRLogin.code = 200; window.QRLogin.uuid = "Ie_lVu7qmQ==";
响应,
返回的response如下:
window.QRLogin.code = 200; window.QRLogin.uuid = "Ie_lVu7qmQ==";
然后拿到uuid,这里式Ie_lVu7qmQ==
,然后渲染到html生成图片
同时在像微信服务器发起如下请求,
https://login.wx.qq.com/cgi-bin/mmwebwx-bin/login?loginicon=true&uuid=wbvMiDtJMw==&tip=1&r=-1055033147&_=1525768422635
然后进行检测,看是否有手机扫码登陆,微信服务器处于pending状态,一直在等待手机扫码登陆,如果在某个时间段(大概半分钟),没有手机扫码登陆,就返回408状态码,然后再次微信服务器处于pending状态
以下式window.code=408;
响应截图
然后用手机扫码操作
ret = requests.get(check_url)
print("ret.text~~~~~~~",ret.text)
输出如下
ret.text~~~~~~~ window.code=201;window.userAvatar = 'data:img/jpg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAoHBwgHBgoICAgLCgoLDhgQDg0NDh0VFhEYIx8lJCIfIiEmKzcvJik0llSiiGBDoooomB/9k=';
window.code=200;
window.redirect_uri="https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxnewloginpage?ticket=AbczicMqBfNXxYuJs5G0CbRy@qrticket_0&uuid=oamap_bsaQ==&lang=zh_CN&scan=1525770582";
然后会继续在redirect_uri
发请求
https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxnewloginpage?ticket=ARsBaAiUYgJbySWbtovgZyVd@qrticket_0&uuid=Ibo3sJnmJQ==&lang=zh_CN&scan=1525771779&fun=new&version=v2&lang=zh_CN
<error>
<ret>0ret>
<message>message>
<skey>@crypt_56c6e845_49bcf817dfc65bb4142170e355cf0ab2skey
><wxsid>W7TXjDJ6pmok5Sbmwxsid>
<wxuin>2404580303wxuin>
<pass_ticket>OHHPpM8kNYzmK7XrKaYDJ3OtO7HldKT2REIuj148Fs%2FKNXEIOVKz0Ip%2FW6HbYghpass_ticket>
<isgrayscale>1isgrayscale>
error>
然后渲染页面信息即可
from flask import Flask, request, render_template, session, jsonify
import time
import requests
import re
from bs4 import BeautifulSoup
import json
app = Flask(__name__)
app.debug = True
app.secret_key = 'asdf3sdfsdf'
def xml_parser(text):
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():
if request.method == 'GET':
ctime = str(int(time.time() * 1000))
qcode_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}".format(
ctime)
ret = requests.get(qcode_url)
qcode = re.findall('uuid = "(.*)";', ret.text)[0]
session['qcode'] = qcode
return render_template('login.html', qcode=qcode)
else:
pass
@app.route('/check_login')
def check_login():
"""
发送GET请求检测是否已经扫码、登录
https://login.wx.qq.com/cgi-bin/mmwebwx-bin/login?loginicon=true&uuid=QbeUOBatKw==&tip=0&r=-1036255891&_=1525749595604
:return:
"""
response = {'code': 408}
qcode = session.get('qcode')
ctime = str(int(time.time() * 1000))
check_url = "https://login.wx.qq.com/cgi-bin/mmwebwx-bin/login?loginicon=true&uuid={0}&tip=0&r=-1036255891&_={1}".format(
qcode, ctime)
ret = requests.get(check_url)
print("ret.text~~~~~~~", ret.text)
if "code=201" in ret.text:
# 扫码成功
src = re.findall("userAvatar = '(.*)';", ret.text)[0]
response['code'] = 201
response['src'] = src
elif 'code=200' in ret.text:
# 确认登录
print("code=200~~~~~~~", ret.text)
redirect_uri = re.findall('redirect_uri="(.*)";', ret.text)[0]
# 向redirect_uri地址发送请求,获取凭证相关信息
redirect_uri = redirect_uri + "&fun=new&version=v2"
ticket_ret = requests.get(redirect_uri)
ticket_dict = xml_parser(ticket_ret.text)
session['ticket_dict'] = ticket_dict
response['code'] = 200
return jsonify(response)
@app.route('/index')
def index():
"""
用户数据的初始化
https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxinit?r=-1039465096&lang=zh_CN&pass_ticket=q9TOX4RI4VmNiHXW9dUUl1oMzoQK2X2f3H3kn0VYm5YGNwUMO2THYMznv8DSXqp0
:return:
"""
ticket_dict = session.get('ticket_dict')
init_url = "https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxinit?r=-1039465096&lang=zh_CN&pass_ticket={0}".format(
ticket_dict.get('pass_ticket'))
data_dict = {
"BaseRequest": {
"DeviceID": "e750865687999321",
"Sid": ticket_dict.get('wxsid'),
"Uin": ticket_dict.get('wxuin'),
"Skey": ticket_dict.get('skey'),
}
}
init_ret = requests.post(
url=init_url,
json=data_dict
)
init_ret.encoding = 'utf-8'
user_dict = init_ret.json()
print(user_dict)
# for user in user_dict['ContactList']:
# print(user.get('NickName'))
return render_template('index.html', user_dict=user_dict)
if __name__ == '__main__':
app.run()
login页面
<html lang="zh-cn">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Titletitle>
head>
<body>
<div style="width: 200px;margin: 0 auto">
<h1 style="text-align: center">微信登录h1>
<img id="img" style="height: 200px;width: 200px;" 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.html
<html lang="zh-cn">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Titletitle>
head>
<body>
<h1>欢迎登录:{{user_dict.User.NickName}}h1>
<h3>最近联系人h3>
<ul>
{% for user in user_dict.ContactList%}
<li>{{user.NickName}}li>
{% endfor %}
ul>
body>
html>