利用爬虫模拟网页微信wechat

1.登录页面,显示二维码

当我们打开网页微信时,会看到一个用于扫码登录的二维码,所以我们要模拟该页面给我们的页面也弄一个二维码

通过查看网页代码我们发现,这个二维码的标签为

这个src属性的最后一段每次访问都是不同的,我们发现每次访问该页面时,会向后端发送请求获得这个随机字符串

这个请求的结果为

所以该请求获取的结果就是我们想要的随机字符串,那么我们也可以向这个url发送请求,获取随机字符串,并利用随机字符串拼接地址获取二维码图片

from flask import Flask, request, render_template, session
import time
import requests
import re
app = Flask(__name__)
app.debug = True
app.secret_key = 'ksjgs'@app.route('/login', methods=['GET', 'POST'])
def login():if request.method == 'GET':ctime = str(int(time.time() * 1000))  # url最后的内容其实是时间戳经过处理的结果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&_={}'.format(ctime)ret = requests.get(qcode_url)qcode = re.findall('uuid = "(.*)";', ret.text)[0]session['qcode'] = qcodereturn render_template('login.html', qcode=qcode)else:passif __name__ == '__main__':app.run()

login页面

<!DOCTYPE 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>微信登录</title>
</head>
<body>
<h1>微信登录</h1>
<img src="https://login.weixin.qq.com/qrcode/{{qcode}}" alt="">
<script src="/static/jquery-3.2.1.min.js"></script></body>
</html>

这样,我们访问时就能看到二维码了

扫码后二维码变成用户头像

看到二维码后如果我们进行了扫码,那么页面上的二维码会立刻变成用户的头像,但是此时我们并没有看到页面向后端发送请求,为什么后端能让前端的页面发生变化呢,我们通过浏览器的network选项发现,其实当页面加载完成后,浏览器会不停的向后端的一个url发送

请求,这个请求发送到后端后就被夯住了,这个时间在25秒左右,如果没有人扫码,那么请求会结束,浏览器继续发送,如果有人扫码了,那么后端会立刻向浏览器返回相关信息,浏览器就可以将页面的二维码改变为用户的头像了,这种持续发送请求的方式称为长轮询

我们在页面加载完成后也模拟这个长轮询

login页面

<!DOCTYPE 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>微信登录</title>
</head>
<body>
<h1>微信登录</h1>
<img src="https://login.weixin.qq.com/qrcode/{{qcode}}" alt="">
<script src="/static/jquery-3.2.1.min.js"></script>
<script>$(function () {check_login()});function check_login() {$.ajax({url: '/check_login',type: 'GET',dataType: 'JSON',success:function (arg) {if (arg.code === 201){$('img').attr('src', arg.src);check_login()} else if(arg.code === 200){location.href = '/index'}else{check_login()}}})}
</script>
</body>
</html>

前端页面加载完成后就开始向后端发送ajax长轮询,根据后端返回的内容判断是否继续发送轮询还是进行跳转,如果有人扫码了,那么就将扫码人的头像替换页面上的二维码,并继续轮询,直到扫码人点击确认,则进行跳转,没人扫码则一直进行长轮询

后端

from flask import Flask, request, render_template, session, jsonify
import time
import requests
import re
from bs4 import BeautifulSoupapp = Flask(__name__)
app.debug = True
app.secret_key = 'ksjgs'def xml_parser(text):"""<error><ret>0</ret><message></message><skey>@crypt_ef73b06b_bd2d7a9918de33c9fc59b3b518a5314f</skey><wxsid>5gfJFQAju+rnuD3t</wxsid><wxuin>2507632864</wxuin><pass_ticket>n3hBG1Aky%2FORERALnTUhkjRrAaho%2BX6vu8%2B9Z3gPrsmnWmKqs5a%2BFe%2FehjeweCeP</pass_ticket><isgrayscale>1</isgrayscale></error> """dic = {}soup = BeautifulSoup(text, 'html.parser')div = soup.find(name='error')for item in div.find_all(recursive=False):dic[item.name] = item.textreturn dic@app.route('/login', methods=['GET', 'POST'])
def login():if request.method == 'GET':ctime = str(int(time.time() * 1000))  # url最后的内容其实是时间戳经过处理的结果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&_={}'.format(ctime)ret = requests.get(qcode_url)qcode = re.findall('uuid = "(.*)";', ret.text)[0]session['qcode'] = qcodereturn render_template('login.html', qcode=qcode)else:pass@app.route('/check_login')
def check_login():ctime = str(int(time.time() * 1000))qcode = session.get('qcode')check_url = 'https://login.wx.qq.com/cgi-bin/mmwebwx-bin/login?loginicon=true&uuid={}&tip=0&r=-1052355888&_={}'.format(qcode, ctime)ret = requests.get(check_url)response = {'code': 408}  # 如果没人扫码,则返回的code为408if 'code=201' in ret.text:  # 如果有人扫码了,则会返回201,并且会返回用户的头像的srcresponse['code'] = 201response['src'] = re.findall("userAvatar = '(.*)';", ret.text)[0]elif 'code=200' in ret.text:  # 有人扫码后前端页面仍然会发送长轮询,直到扫码的人点击确认登录,会返回200redirect_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)  # 这个登录凭证是一个xml的格式,我们通过一个函数将他转换成字典session['ticket_dict'] = ticket_dict  # 将登录凭证存入session,方便后面使用response['code'] = 200return jsonify(response)@app.route('/index')
def index():return '登录成功'if __name__ == '__main__':app.run()

获取用户信息

当确认登录后,会返回跳转地址,浏览器会向这个跳转地址发送get请求,获取一个凭证(类似于cookie,xml格式),获取这个凭证后,浏览器会接着发送一个post请求,请求内容就是凭证内的相关内容,这个post请求就能获取用户的信息,最近联系人等信息

我们这里通过index函数来发送这个post请求

@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)

首先从session中获取我们处理后得到的凭证字典,然后发送post请求,这里发送的数据为json格式,post请求的返回内容就是用户相关数据的字典,我们可以通过ret.json()直接获取这个字典(相当于经过json.loads),然后将相关的内容渲染到页面上

index页面

<!DOCTYPE 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>Title</title>
</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>

 

 

转载于:https://www.cnblogs.com/weiwu1578/articles/9010561.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/368806.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

爬取饿了么商铺信息

分析&#xff1a; 当我们访问https://www.ele.me/home/时&#xff0c;看看我们得到了什么 1.png我们发现所有的城市名称和他的经纬度&#xff0c;还有一个风流的男子 然后随机输入一些东西看看&#xff0c;进入某个地区看一看 在新的界面里我们看到了这样一条url: https://main…

linux基本命令du,Linux常用操作命令汇总

你还在为不知道Linux常用操作命令汇总而不知所措么?下面来是学习啦小编为大家收集的Linux常用操作命令汇总&#xff0c;欢迎大家阅读&#xff1a;Linux常用操作命令汇总1.ls 命令ls以默认方式显示当前目录文件列表服务器教程ls -a显示所有文件包括隐藏文件ls -l显示文件属性&a…

后处理效果栈

Unity官方的Github实现&#xff1a;Post Processing Stack Post-processing is the process of applying full-screen filters and effects to a camera’s image buffer before it is displayed to screen. It can drastically improve the visuals of your product with litt…

linux 安装tcl命令,TCL/TK Linux下安装 | 勤奋的小青蛙

原创文章&#xff0c;转载请注明&#xff1a; 转载自勤奋的小青蛙本文链接地址: TCL/TK Linux下安装在Linux下安装TCL/TK&#xff0c;可以有编译源代码的方式安装&#xff0c;也可以有直接通过二进制压缩包进行解压缩安装&#xff0c;本文采用比较快捷的方式&#xff0c;用二进…

安全性中的Spring AOP –通过方面控制UI组件的创建

以下文章将显示在我参与的一个项目中&#xff0c;我们如何使用Spring的AOP来介绍一些与安全性相关的功能。 这样的概念是为了使用户能够看到一些UI组件&#xff0c;他需要具有一定级别的安全特权。 如果不满足该要求&#xff0c;则不会显示UIComponent。 让我们看一下项目结构&…

模拟生物自然进化的基因遗传算法

基因遗传算法&#xff08;Genetic Algorithm&#xff0c;GA&#xff09;是一种通过模拟生物进化过程来寻找最优解的优化算法。它是一种常见的启发式搜索算法&#xff0c;常用于优化、搜索和机器学习等领域。 生物基因遗传 生物的基因遗传是指父母通过基因传递给子代的过程。基因…

CSS学习笔记11 CSS背景

background-color&#xff1a;背景色 前面我们经常用background-color这个属性来设置元素的背景色&#xff0c;例如下面这条css可将段落的背景色设置为灰色 p {background-color: gray;} 如果想要元素的背景色向外延伸&#xff0c;则只需增加内边距即可 background-color可以为…

linux 文件的目录,Linux文件及目录管理

第七列&#xff1a;文件或目录名。名以 . 开头表示为隐藏文件或隐藏目录2.2 修改文件目录或者权限改变文件所属用户组&#xff1a;chgrpchgrp [-R] 用户组 文件或目录 ...[-R]&#xff1a;递归修改该目录下所有文件和目录&#xff1b;改变文件所有者&#xff1a;chownchown [-R…

套接字(linux相关)

前言&#xff1a;略 一、前因 一切从tcp、udp开始。 众所周知&#xff0c;网络模型一般有两种模型&#xff0c;一种为OSI概念模型&#xff08;七层&#xff09;&#xff0c;另一种为TCP/IP网络模型&#xff08;四层&#xff09;。 TCP/IP应用层对应OSI的应用层、显示层、会话层…

linux查看进程运行日志文件,【Linux】常用指令、ps查看进程、kill杀进程、启动停止tomcat命令、查看日志、查看端口、find查找文件...

1.说出 10 个 linux 常用的指令1) ls 查看目录中的文件2)cd /home 进入 / home 目录&#xff1b;cd .. 返回上一级目录&#xff1b;cd ../.. 返回上两级目录3)mkdir dir1 创建一个叫做 dir1 的目录4)rmdir dir1 删除一个叫做 dir1 的目录 (只能删除空目录)5)rm -f file1 删除一…

Java PDF库

最近&#xff0c;我有一项任务是选择一些Java PDF库用于PDF生成。 但这不是一个简单的任务。 我想到的第一件事是iText。 众所周知Java库具有良好的声誉。 但是...有一些塞子。 iText 5版是在AGPL许可下发布的。 即&#xff0c;如果我们想在商业产品中使用iText&#xff0c;则必…

前端工程师必备的几个实用网站

一、配色类网站 http://colorhunt.co 这个网站给我们提供了很多的配色方案&#xff0c;我们直接使用就OK了。使用方法也很简单&#xff0c;鼠标移动到对应的颜色上&#xff0c;我们就可以看到颜色的十六进制码&#xff0c;复制这个颜色到工具里就可以使用了。 https://webgra…

linux 修改jmeter内存溢出,jmeter本机内存溢出如何修改?

websocket连接过程中内存溢出&#xff0c;本机配置的内存最大和最小设置的512&#xff1b;一、后台返回二、结果树返回&#xff1a;Thread Name: 线程组 1-9Sample Start: 2017-09-11 13:59:49 CSTLoad time: 9006Connect Time: 0Latency: 0Size in bytes: 0Sent bytes:0Header…

JSF:在传统组件和时尚性能杀手之间进行选择

这篇博客文章起源于一个大型Web应用程序中的性能问题。 每个人都优化Java代码&#xff0c;但似乎没有人尝试优化JavaScript代码。 奇怪&#xff0c;因为在客户端有很多改进的空间。 我会说&#xff0c;甚至比服务器端还要多。 我们将分析可编辑的JSF标准组件&#xff08;有时称…

JS之 if语句函数 对接事件动作 函数更改css css对接需要换妆的区id或class

if 函数的实现步骤: function 名字() 指定id , 指定开关(display: none or block) if else 构成逻辑 控制开关 决定在哪里安置一个灯泡, 指定一个id给某个标签 把开关用电线连着灯泡, 安装开关 # id名称{ 属性1 赋值, 属性 2 赋值 , 属性3 赋值 } 所有的赋值都可以成为一…

小型Hadoop集群的Ganglia配置和一些故障排除

Ganglia是一个针对大型集群的开源&#xff0c;可扩展且分布式的监视系统。 它收集&#xff0c;汇总并提供数十种与计算机相关的指标&#xff08;例如CPU&#xff0c;内存&#xff0c;存储&#xff0c;网络使用情况&#xff09;的时序视图。 您可以在UC Berkeley Grid上看到Gang…

margin赋值为负值的几种效果(负值像素,负值百分数)

1、margin-top为负值像素 margin-top为负值像素&#xff0c;偏移值相对于自身&#xff0c;其后元素受影响&#xff0c;见如下代码&#xff1a; 1 <!DOCTYPE html>2 <html lang"zh">3 <head>4 <meta charset"UTF-8" />5 &…

File如何转换成MultipartFile

MutipartFile是spring里面定义的接口&#xff0c;它封装了用户在上传图片时所包含的所有信息&#xff0c;但是有些时候我们要将file转换成MutipartFile&#xff0c;才能在保持原有代码逻辑的情况下方便代码的调整&#xff0c;但是file不能直接转换成MutipartFile&#xff0c;现…

Vue 进阶教程之:详解 v-model

分享 Vue 官网教程上关于 v-model 的讲解不是十分的详细&#xff0c;写这篇文章的目的就是详细的剖析一下&#xff0c; 并介绍 Vue 2.2 v-model改进的地方&#xff0c;然后穿插的再说点 Vue 的小知识。在 Vue 中&#xff0c;有许多方法和 Angular 相似&#xff0c;这主要是因…

linux 无密码登录另一台服务器,ECS Linux服务器ssh免密码登录另外一台服务器的具体设置...

若有多台linux服务器&#xff0c;为方便起见&#xff0c;服务器之前可设置免密码ssh登录&#xff0c;具体操作参考如下所示&#xff1a;1 、登录其中一个服务器&#xff0c;执行ssh-keygen -t rsa&#xff0c;按3次回车&#xff0c;将会生成公钥和私钥文件id_rsa和id_rsa.pub&a…