一. 项目介绍
1. 项目目的
自动化处理人脸识别。
2. 项目原理
原理在我写的上篇文章:
我们根据上篇文章知道,他这个人脸识别主要就这几个参数
- clazzid
- courseId
- uuid
- qrcEnc
- objectId
这几个参数怎么整出来的我也说了,其中clazzId
、uuid
和qrcEnc
这三个参数可以直接从页面弹出的二维码链接里得到,courseId
需要你自己找,objectId
是程序自己生成的。
3. 项目流程
现在捋一下项目流程
- 自己找到
courseId
参数(懒得做了)
- 从客户端得到二维码链接
- 将二维码链接发送给服务端
- 服务端处理URL,提取
clazzId
、uuid
和qrcEnc
这三个参数
- 进行人脸识别,得到
objectId
参数
- 根据参数进行授权
4. 流程理论实现
先说第一个,自己找(主要是懒得写了),怎么找我上篇文章说了
第二步,从客户端得到二维码链接。这里的客户端就是本地浏览器了,从页面获取链接,我想到的是用JS检测DOM树来实现。
第三步,将二维码链接发送给服务端。这一步本来是打算和第二步放一起的,但是这步实现对于我来说有点难受,于是单独拿出来讲讲。服务端就是python了。用python建立个服务器,然后接收JS传来的数据就行了。
第四步,服务端处理URL,提取clazzId
、uuid
和qrcEnc
这三个参数。这步简单,编码处理和正则就行了。
第五步,进行人脸识别,得到objectId
参数,这一步上篇文章整完了,主要就是用一张随机图片作为人脸图片上传到接口,从而骗过对方服务器得到objectId
参数。
第六步,根据参数进行授权,没啥好说的,直接传接口拿授权就行了。
二. 项目实现
1. Python服务搭建
这里用了好多个库,最后选择用websockets
库,这过程在之后JS传递数据那里出了一堆问题。最后有了该代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| import websockets
async def receive_image_link(websocket, path): while True: try: image_link = await websocket.recv() url = urllib.parse.unquote(image_link) print(f"Received image link: {url}") await websocket.send("Processed and close") # 处理完成后发送消息给客户端 except websockets.exceptions.ConnectionClosedOK: print("WebSocket连接已关闭") print("=" * 50) break start_server = websockets.serve(receive_image_link, "127.0.0.1", 4200) async def main(): server = await start_server print(f"WebSocket 服务器已启动,正在监听 {server.sockets[0].getsockname()}") await server.wait_closed() asyncio.get_event_loop().run_until_complete(main())
|
这里用websockets
库搞了一个WebSocket服务器,监听本地的4200端口,等待客户端连接。
receive_image_link
函数这里搞了一个异步,用于处理接收到的消息。用一个无限循环来不断接收客户端发送的消息。当接收到消息时,它会对消息进行处理,并发送一个回复消息给客户端。
在main
函数中,首先通过websockets.serve
函数创建一个WebSocket服务器,并指定监听的IP地址和端口。然后,打印服务器启动的信息。
最后,通过asyncio.get_event_loop().run_until_complete
来运行main
函数,使服务器一直运行,直到被关闭。
总结,没啥难度。主要是这个异步的处理
下面放一个运行截图

2. 人脸识别脚本
上篇文章讲过,这里不在过多赘述
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55
| import string import time import random import cv2 import numpy as np import requests from requests_toolbelt import MultipartEncoder def random_picture(): print("正在生成图片……") d = 400 img = np.ones((d, d, 3), np.uint8) * 255 for i in range(0, 100): center_x = np.random.randint(0, high=d) center_y = np.random.randint(0, high=d) radius = np.random.randint(5, high=d / 5) color = np.random.randint(0, high=256, size=(3,)).tolist() cv2.circle(img, (center_x, center_y), radius, color, -1) cv2.imwrite("1.jpg", img) def face(): print("正在处理人脸识别……") url = "https://pan-yz.chaoxing.com/upload?uploadtype=face" headers = { "Cookie": "", "User-Agent": "", "Host": "pan-yz.chaoxing.com", } rand_str = ''.join(random.sample(string.ascii_letters + string.digits, 16)) random_picture() file = open('1.jpg', 'rb') body = MultipartEncoder( fields={ '_token': 'ca2f75fa81f41ccdbc9a613314ef9890', 'puid': '244263407', 'file': (f"{str(int(time.time() * 1000))}.jpg", file, 'image/jpg'), }, boundary=f'Boundary+{rand_str}') contentype = body.content_type headers['content-type'] = contentype response = requests.post(url, headers=headers, data=body) objectId = response.json()["objectId"] print(objectId) return objectId
|
没啥好讲的。会的都会。
3. 授权
上篇文章也讲过,这里不在过多赘述
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| # coding=utf-8 import re import urllib import requests from 人脸识别模块 import face # 主程序 def authorize(message): print("正在授权……") url = "https://mooc1-api.chaoxing.com/mooc-ans/qr/updateqrstatus" new_txt = urllib.parse.unquote(message) for i, ii, iii in re.findall('uuid=(.*?)&clazzid=(.*?)&enc=(.*?)&', new_txt): uuid = i clazzid = ii enc = iii params = { "clazzId": clazzid, "courseId": "204589142", "uuid": uuid, "qrcEnc": enc, "objectId": face() } headers = { "Origin": "https://mooc1-api.chaoxing.com", "Cookie": "", "Referer": "", "User-Agent": "", "Host": "mooc1-api.chaoxing.com" } response = requests.post(url, headers=headers, params=params) print(response.text)
|
4. JS客户端
博主JS不咋地,就是简单的学了学,在写这代码的时候直接给我干发烧了……然后解决了一堆BUG,得到了以下代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
| // ==UserScript== // @name 学习通人脸识别二维码链接 // @namespace http://tampermonkey.net/ // @version 0.1 // @description 获取学习通人脸识别二维码的链接 // @author 特让他也让 // @include * // @require https://scriptcat.org/lib/513/2.0.0/ElementGetter.js // ==/UserScript== // 客户端代码(JavaScript)
// 等待渲染模块 document.addEventListener("DOMContentLoaded", function(event) { // 在页面渲染完毕后运行检测模块 checkWindowAndImage(); });
// 检测模块 function checkWindowAndImage() { const windowDiv = document.querySelector(".popDiv.wid640.faceCollectQrPop.popClass"); if (windowDiv) { const image = windowDiv.querySelector("#fcqrimg"); if (image) { processData(image.src); return; } } setTimeout(checkWindowAndImage, 1000); // 页面加载完成后,每隔1秒检测一次窗口和图片是否存在 }
// 数据处理模块 function processData(imageSrc) { // 处理图片链接 const processedData = imageSrc;
sendToServer(processedData); }
// 发送模块 function sendToServer(data) { const websocket = new WebSocket("ws://127.0.0.1:4200"); // 连接到 python 服务器
websocket.onopen = function () { console.log("WebSocket 连接已建立"); websocket.send(data); };
websocket.onmessage = function (event) { console.log("接收到服务器响应: " + event.data); websocket.close(); endModule(); }; }
// 结束模块 function endModule() { console.log("连接已关闭"); // 在连接关闭后等待2秒后重新运行检测模块 setTimeout(checkWindowAndImage, 2000); }
// 运行检测模块 checkWindowAndImage();
|
这是写的油猴脚本,直接放油猴里运行就行了

在油猴里打开就行了。
三. 完整项目文件
链接:https://wwnq.lanzoub.com/iQlVp1ebl5ng