利用爬虫模拟网页微信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
總結
以上是生活随笔為你收集整理的利用爬虫模拟网页微信wechat的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【2017级面向对象程序设计】第2次成绩
- 下一篇: 后处理效果栈