为了能够模拟登陆QQ,并获取信息。对扫码登录微信进行了分析。简单的用了一下Django将获取的信息映射到页面上。(python3+pycharm)

主要过程就是:

1、获取二维码

2、扫码登录(有三种状态)

3、获取联系人信息(index页面获取的是个人信息、最近联系人信息、公众号)

4、获取所有的联系人

5、发送和接收消息(接收消息打印到了后台)

创建Django项目、导入JQuery(发送AJax请求)、创建APP、创建模板(简单的弄一下,能合理显示得到的数据就好)

url.py

from django.contrib import admin
# from django.urls import path
from django.conf.urls import url
from app01 import views
urlpatterns = [
url('admin/', admin.site.urls),
url(r'^$', views.login), # 显示登录二维码
url(r'^polling/$', views.long_polling), # 长轮询
url(r'^index/$', views.index), #
url(r'^contact_list/$', views.contact_list),# 获取全部的联系人
url(r'^send_msg/$', views.send_msg), # 发送消息
url(r'^get_msg/$', views.get_msg), # 接收消息
]

templates

login.html(对应的是views中函数login和long_polling)

扫码前

扫码后、没有点击登录按钮,显示的你的头像

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body> <div style="margin: 0 auto;width: 300px">
<img id="qcode" style="width: 300px;height: 300px" src="https://login.weixin.qq.com/qrcode/{{ code }}" alt="扫码登录">
</div> <script src="/static/jquery-1.12.4.js"></script>
<script>
$(function () { polling();
});
function polling(){
$.ajax({
url: '/polling/',
type: 'GET',
dataType: 'json',
success: function (arg) {
if(arg.status==408){
console.log(1); polling();
}else if(arg.status==201){
$('#qcode').attr('src',arg.data);
polling(); }else if(arg.status==200) {
window.location.href ='/index/';
} } })
}
</script>
</body>
</html>

index.html(个人信息、最近联系人、公众号页面)

点击登录后的页面:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>个人信息</h1>
<div>
{# <img src="https://wx.qq.com{{ data.User.HeadImgUrl }}">#}
<img style="width: 40px;height: 40px" src={{ code }}>
</div>
<div>
{{ data.User.NickName }} - {{ data.User.UserName }}
</div>
<h1>最近联系人列表</h1>
<ul>
{% for row in data.ContactList%}
<li>{{ row.UserName }} - {{ row.NickName }}</li>
{% endfor %}
<li><a href="/contact_list/">获取更多联系人</a></li>
</ul> <h1>公众号</h1>
{% for row in data.MPSubscribeMsgList%}
<div style="font-weight: bolder">{{ row.NickName }}</div>
{% for i in row.MPArticleList %}
<div>
<div><a href="{{ i.Url }}">{{ i.Title }}</a></div>
<div style="color: #dddddd">{{ i.Digest }}</div>
</div> {% endfor %} {% endfor %} </body>
</html>

contac_list(全部联系人、发送接收页面)

页面:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>发送消息</h1>
<div> <p><input id="user_id" type="text" placeholder="请输入用户唯一ID" /></p>
<p><input id='user_msg' type="text" placeholder="请输入内容" /></p>
<input id="sendMsg" type="button" value="提交" />
</div>
<ul>
{% for row in obj.MemberList %}
<li>{{ row.NickName }} - {{ row.UserName }} -{{ row.Province }}</li>
{% endfor %}
</ul>
<script src="/static/jquery-1.12.4.js"></script>
<script>
$(function () {
bindSendMessage();
fetchMessage();
});
function bindSendMessage() {
$('#sendMsg').click(function () {
$.ajax({
url: '/send_msg/',
type: 'POST',
data: {'user_id': $('#user_id').val(), 'user_msg': $('#user_msg').val()},
success:function () { }
})
});
} function fetchMessage(){
$.ajax({
url: '/get_msg/',
type: 'GET',
success:function (arg) {
fetchMessage();
}
})
}
</script>
</body>
</html>

views.py(逻辑层)

import re
import time
import json
import requests
from bs4 import BeautifulSoup
from django.shortcuts import render, HttpResponse
# Create your views here. # 一些全局变量
# 当前时间戳
CURRENT_TIME = None
# 验证码
QCODE = None
#图片
PICTURE = None
# tip
TIP = 1
# LOGININ cookies
# all_cookie_dict = {}
# 保存cookies
LOGIN_COOLIES_DICT = {}
TICKET_COOKIES_DICT = {}
TICKET_DICT = {}
# 用户信息
USER_INIT_DATA = {} def login(request):
'''
获取登录二维码
:param request:
:return:
'''
global QCODE
global CURRENT_TIME 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}'
CURRENT_TIME = str(time.time())
q_code_url = url.format(CURRENT_TIME)
response = requests.get(q_code_url)
# 打印返回值
# window.QRLogin.code = 200; window.QRLogin.uuid = "4c5VeLH00g==";
# print(response.text)
code = re.findall('uuid = "(.*)";', response.text)[0]
QCODE = code
# print(code)
return render(request, 'login.html', {'code': code}) def long_polling(request):
'''
长轮询,有408、201、200三种状态
:param request:
:return:
''' global TIP
global PICTURE
print('polling') # 默认返回Ajax状态为408
ret = {'status': 408, 'data': None}
base_login_url = 'https://login.wx.qq.com/cgi-bin/mmwebwx-bin/login?loginicon=true&uuid={0}&tip={1}&r=970980966&_={1}'
login_url = base_login_url.format(QCODE, TIP, CURRENT_TIME)
response = requests.get(login_url)
# print(response.text) # 判断
if 'window.code=201' in response.text:
TIP = 0
# 图片地址
avatar = re.findall("userAvatar = '(.*)';", response.text)[0]
# print(avatar)
ret['data'] = avatar
ret['status'] = 201
# 获得个人信息头像使用(index函数中,直接在函数返回值中提取链接获取不到图片)
PICTURE = avatar elif 'window.code=200' in response.text:
# 获取登录时的cookie值,存到全局变量中
LOGIN_COOLIES_DICT.update(response.cookies.get_dict())
# 提取返回值中的url地址
redirect_uri = re.findall('redirect_uri="(.*)";', response.text)[0]
redirect_uri += '&fun=new&version=v2' # 获取以后要用到的ticket等数据
response_ticket = requests.get(redirect_uri, cookies=LOGIN_COOLIES_DICT)
TICKET_COOKIES_DICT.update(response_ticket.cookies.get_dict())
# print(response_ticket.text)
# soup1 = BeautifulSoup(response_ticket.text, 'lxml')
soup2 = BeautifulSoup(response_ticket.text, 'html.parser')
# print(soup1)
# print(soup2)
for tag in soup2.find():
TICKET_DICT[tag.name] = tag.string
# print(TICKET_DICT)
ret['status'] = 200
return HttpResponse(json.dumps(ret)) def index(request):
'''
获取个人信息、最近联系人、公众号
:param request:
:return:
'''
# 用户初始化
user_init_url = 'https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxinit?r=855409185&pass_ticket=%s' % TICKET_DICT['pass_ticket']
form_data = {
'BaseRequest': {
'DeviceID': 'e531777446530354',
'Sid': TICKET_DICT['wxsid'],
'Skey': TICKET_DICT['skey'],
'Uin': TICKET_DICT['wxuin']
}
} # 带上所有的coolkie
all_cookie_dict = {}
all_cookie_dict.update(LOGIN_COOLIES_DICT)
all_cookie_dict.update(TICKET_COOKIES_DICT)
# json= 发送过去会自动带一个请求头,用json解析
response_init = requests.post(user_init_url, json=form_data, cookies=all_cookie_dict)
# print(response_init.text)
response_init.encoding = 'utf-8'
# print(response_init.text)
user_init_data = json.loads(response_init.text)
USER_INIT_DATA.update(user_init_data) return render(request, 'index.html', {'data': user_init_data, 'code':PICTURE}) def contact_list(request):
'''
获取所有联系人列表
:param request:
:return:
'''
# print(all_cookie_dict)
# print(TICKET_DICT)
# print(LOGIN_COOLIES_DICT)
# print(TICKET_COOKIES_DICT) url = ("https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxgetcontact?lang=zh_CN&pass_ticket=%s&r=%s&seq=0&skey=%s" % \
(TICKET_DICT['pass_ticket'], str(time.time()), TICKET_DICT['skey']))
# base_url = '{0} {1} {2}'
# url = base_url.format(TICKET_DICT['pass_ticket'], str(time.time()), TICKET_DICT['skey'])
# print(base_url)
all_cookie_dict = {}
all_cookie_dict.update(LOGIN_COOLIES_DICT)
all_cookie_dict.update(TICKET_COOKIES_DICT)
response = requests.get(url, cookies=all_cookie_dict)
response.encoding = 'utf-8'
contact_list_dict = json.loads(response.text)
# print(contact_list_dict)
return render(request, 'contact_list.html', {'obj': contact_list_dict})
# return HttpResponse("ok") def send_msg(request):
'''
发送消息
:param request:
:return:
'''
# print(USER_INIT_DATA)
# print(TICKET_DICT)
# print(LOGIN_COOLIES_DICT)
# print(TICKET_COOKIES_DICT)
from_user_id = USER_INIT_DATA['User']['UserName']
to_user_id = request.POST.get('user_id')
msg = request.POST.get('user_msg')
send_url = 'https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxsendmsg'
form_data = {
'BaseRequest': {
'DeviceID': 'e531777446530354',
'Sid': TICKET_DICT['wxsid'],
'Skey': TICKET_DICT['skey'],
'Uin': TICKET_DICT['wxuin']
},
'Msg': {
"ClientMsgId": str(time.time()),
#"Content": msg,
"Content": '%(content)s',
"FromUserName": from_user_id,
"LocalID": str(time.time()),
"ToUserName": to_user_id,
"Type": 1
},
'Scene': 0
}
import json
# 字符串
form_data_str = json.dumps(form_data)
# 进行格式化
form_data_str = form_data_str % {'content': msg} # 转换成字节
form_data_bytes = bytes(form_data_str, encoding='utf-8') all_cookie_dict = {}
all_cookie_dict.update(LOGIN_COOLIES_DICT)
all_cookie_dict.update(TICKET_COOKIES_DICT) # response = requests.post(send_url, json=form_data, cookies=all_cookie_dict)
response = requests.post(send_url, data=form_data_bytes, cookies=all_cookie_dict, headers={
'Content-Type': 'application/json'})
print(response.text)
return HttpResponse('OK') def get_msg(request):
sync_url = 'https://webpush.wx.qq.com/cgi-bin/mmwebwx-bin/synccheck' sync_data_list = []
for item in USER_INIT_DATA['SyncKey']['List']:
temp = "%s_%s" % (item['Key'], item['Val'])
sync_data_list.append(temp)
sync_data_str = "|".join(sync_data_list)
nid = int(time.time())
sync_dict = {
"r": nid,
"skey": TICKET_DICT['skey'],
"sid": TICKET_DICT['wxsid'],
"uin": TICKET_DICT['wxuin'],
"deviceid": "e531777446530354",
"synckey": sync_data_str
}
all_cookie = {}
all_cookie.update(LOGIN_COOLIES_DICT)
all_cookie.update(TICKET_COOKIES_DICT)
response_sync = requests.get(sync_url, params=sync_dict, cookies=all_cookie)
print(response_sync.text)
if 'selector:"2"' in response_sync.text:
fetch_msg_url = "https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxsync?sid=%s&skey=%s&lang=zh_CN&pass_ticket=%s" % (
TICKET_DICT['wxsid'], TICKET_DICT['skey'], TICKET_DICT['pass_ticket']) form_data = {
'BaseRequest': {
'DeviceID': 'e531777446530354',
'Sid': TICKET_DICT['wxsid'],
'Skey': TICKET_DICT['skey'],
'Uin': TICKET_DICT['wxuin']
},
'SyncKey': USER_INIT_DATA['SyncKey'],
'rr': str(time.time())
}
response_fetch_msg = requests.post(fetch_msg_url, json=form_data)
response_fetch_msg.encoding = 'utf-8'
res_fetch_msg_dict = json.loads(response_fetch_msg.text)
USER_INIT_DATA['SyncKey'] = res_fetch_msg_dict['SyncKey']
for item in res_fetch_msg_dict['AddMsgList']:
print(item['Content'], ":::::", item['FromUserName'], "---->", item['ToUserName'],)
return HttpResponse('ok')

爬虫入门简单,想要深入果然很难。继续努力,加油!

十一、模拟扫码登录微信(用Django简单的布置了下页面)发送接收消息的更多相关文章

  1. 微信开放平台开发——网页微信扫码登录(OAuth2.0)

    1.OAuth2.0 OAuth(开放授权)是一个开放标准,允许用户让第三方应用访问该用户在某一网站上存储的私密的资源(如照片,视频,联系人列表),而无需将用户名和密码提供给第三方应用. 允许用户提供 ...

  2. 第三方登录:微信扫码登录(OAuth2.0)

    1.OAuth2.0 OAuth(开放授权)是一个开放标准,允许用户让第三方应用访问该用户在某一网站上存储的私密的资源(如照片,视频,联系人列表),而无需将用户名和密码提供给第三方应用. 允许用户提供 ...

  3. php微信开放平台--第三方网页微信扫码登录(OAuth2.0)

    第一.OAuth2.0 OAuth(开放授权)是一个开放标准,允许用户让第三方应用访问该用户在某一网站上存储的私密的资源(如照片,视频,联系人列表),而无需将用户名和密码提供给第三方应用. 允许用户提 ...

  4. Web应用多账号系统设计及微信扫码登录实现

    Web应用多账号系统设计及微信扫码登录实现 1   前言概述 公司对功能测试,性能测试,安全测试等等都做了比较好的自动化后,急需要一个MIS系统来统一管理这些结果及报表. 此MIS系统特点如下: 仅内 ...

  5. C#开发微信门户及应用(45)--微信扫码登录

    在前面随笔<C#开发微信门户及应用(41)--基于微信开放平台的扫码登录处理>介绍了基于微信开放平台接口实现的微信扫码直接登录的过程.本篇介绍对扫码登录的一些改进和处理,以便更方便应用在实 ...

  6. C#开发微信门户及应用(41)--基于微信开放平台的扫码登录处理

    在现今很多网站里面,都使用了微信开放平台的扫码登录认证处理,这样做相当于把身份认证交给较为权威的第三方进行认证,在应用网站里面可以不需要存储用户的密码了.本篇介绍如何基于微信开放平台的扫码进行网站的登 ...

  7. 微信小程序使用场景延伸:扫码登录、扫码支付

    微信小程序使用场景延伸:扫码登录.扫码支付 小程序最适合的使用场景有哪些?相比大家能列举出来很多,但这个场景,大家可能多数没想到_^ 笔者团队近期接到了一个PC项目:转转游戏租号PC官网,该项目要求在 ...

  8. Vue+abp微信扫码登录

    最近系统中要使用微信扫码登录,根据微信官方文档和网络搜索相关文献实现了.分享给需要的人,也作为自己的一个笔记.后端系统是基于ABP的,所以部分代码直接使用了abp的接口,直接拷贝代码编译不通过. 注册 ...

  9. Java实现微信客户端扫码登录

    此篇文章记录自己开发中的微信客户端扫码登录的实例以及步骤,便于以后自行学习记起的关键,看到的网友有借鉴的地方就借鉴,看不懂的也请别吐槽,毕竟每个人的思维和思路以及记录东西的方式不一样: 1.首先需要一 ...

随机推荐

  1. Queries for Number of Palindromes(区间dp)

    You've got a string s = s1s2... s|s| of length |s|, consisting of lowercase English letters. There a ...

  2. JDK15就要来了,你却还不知道JDK8的新特性!

    微信搜「烟雨星空」,白嫖更多好文. 现在 Oracle 官方每隔半年就会出一个 JDK 新版本.按时间来算的话,这个月就要出 JDK15 了.然而,大部分公司还是在使用 JDK7 和 8 . 之前去我 ...

  3. 【原创】如何优雅的转换Bean对象

    背景 我们的故事要从一个风和日丽的下午开始说起! 这天,外包韩在位置上写代码-外包韩根据如下定义 PO(persistant object):持久化对象,可以看成是与数据库中的表相映射的 java 对 ...

  4. Java垃圾回收略略观

    本文主要介绍Java垃圾回收(Garbage Collection),90%干货,文字颇多,需要耐心一点看. [对象判断状态算法] ------引用计数法 在创建对象时,为对象创建一个伴生的引用计数器 ...

  5. map 地图组件

    地图选择器网址 http://datav.aliyun.com/tools/atlas/#&lat=31.769817845138945&lng=104.29901249999999& ...

  6. 写给.NET开发者的Python教程(三):运算符、条件判断和循环语句

    本节会介绍Python中运算符的用法,以及条件判断和循环语句的使用方法. 运算符 运算符包括算术运算符.赋值运算符.比较运算符.逻辑运算符等内容,大部分用法和C#基本一致,下面我们来看一下: 算数运算 ...

  7. window.location.href跳转无效

    window.location.href跳转无效     问题情况 JS中设置window.location.href跳转无效   原因是 a标签的href跳转会执行在window.location. ...

  8. .net mvc web api上传图片/文件并重命名

    #region 上传图片 /// <summary> /// 上传图片到服务器 当error为0时成功,为1时失败 并从errmsg获取消息 /// </summary> // ...

  9. Zookeeper启动流程分析

    前言 之前的Zookeeper协议篇-Paxos算法与ZAB协议通过了解Paoxs算法开始,到Zab协议的两大特性:崩溃恢复和消息广播,学习了Zookeeper是如何通过Zab协议实现高可用,本篇主要 ...

  10. TaskContinuationsOptions.ExecuteSynchronously探秘

    TPL - Task Parallel Library为我们提供了Task相关的api,供我们非常方便的编写并行代码,而不用自己操作底层的Thread类.使用Task的优势是显而易见的: 提供返回值 ...