一. 项目介绍

1. 项目目的

自动化处理人脸识别。

2. 项目原理

原理在我写的上篇文章:

我们根据上篇文章知道,他这个人脸识别主要就这几个参数

  • clazzid
  • courseId
  • uuid
  • qrcEnc
  • objectId

这几个参数怎么整出来的我也说了,其中clazzIduuidqrcEnc这三个参数可以直接从页面弹出的二维码链接里得到,courseId需要你自己找,objectId是程序自己生成的。

3. 项目流程

现在捋一下项目流程

  • 自己找到courseId参数(懒得做了)
  • 从客户端得到二维码链接
  • 将二维码链接发送给服务端
  • 服务端处理URL,提取clazzIduuidqrcEnc这三个参数
  • 进行人脸识别,得到objectId参数
  • 根据参数进行授权

4. 流程理论实现

先说第一个,自己找(主要是懒得写了),怎么找我上篇文章说了

第二步,从客户端得到二维码链接。这里的客户端就是本地浏览器了,从页面获取链接,我想到的是用JS检测DOM树来实现。

第三步,将二维码链接发送给服务端。这一步本来是打算和第二步放一起的,但是这步实现对于我来说有点难受,于是单独拿出来讲讲。服务端就是python了。用python建立个服务器,然后接收JS传来的数据就行了。

第四步,服务端处理URL,提取clazzIduuidqrcEnc这三个参数。这步简单,编码处理和正则就行了。

第五步,进行人脸识别,得到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