小猿口算思路总结(附代码+教程)

以下仅供学习交流使用,禁止用于其他用途,如果侵权,请联系作者删除!!!

仅供学习!!!

仅供学习!!!

仅供学习!!!

一.ocr识别

原理:捕捉屏幕的图片,进行特定区域文字识别。

优点:环境配置简单,易上手,且不容易被封。

缺点:速度比较慢,大概是大学生水准,并且有错误,需要自己优化。

下面第一个代码是主代码,第二个是辅助你获取坐标的,第一个代码有些部分需要你改一下

使用教程:下载一个模拟器,下载一个Tesseract,然后代码中路径填写为你的Tesseract路径,然后,用辅助代码获取你的区域坐标,更改主代码中的坐标即可。

主代码: 

import cv2
import numpy as np
import pytesseract
import mss
import pyautogui
import time
from threading import Thread, Lock

# 设置Tesseract可执行文件路径   请自行安装 并更换成你的路径
pytesseract.pytesseract.tesseract_cmd = r'D:\see\tesseract.exe'

# 定义捕获区域,左上角和右下角坐标    题目的坐标
current_top_left = (71, 364)
current_bottom_right = (810, 760)

# 计算当前题目区域的宽度和高度
current_monitor = {
    "top": current_top_left[1],
    "left": current_top_left[0],
    "width": current_bottom_right[0] - current_top_left[0],
    "height": current_bottom_right[1] - current_top_left[1]
}

# 存储上一个绘制的符号
last_numbers = None  # 用于记录上一次的数字
lock = Lock()  # 创建一个锁以保证线程安全


def draw_symbol_with_mouse(symbol, position):
    x, y = position
    pyautogui.moveTo(x, y)  # 移动到指定位置
    pyautogui.mouseDown()  # 按下鼠标左键

    # 减少移动步骤
    if symbol == ">":
        pyautogui.moveRel(30, -30)  # 添加 duration 减少移动时间
        pyautogui.moveRel(-30, -30)
    elif symbol == "<":
        pyautogui.moveRel(-30, -30)
        pyautogui.moveRel(30, -30)

    pyautogui.mouseUp()  # 放开鼠标左键


def print_result(numbers, comparison):
    print(f"识别到的数字: {numbers[0]} 和 {numbers[1]}, 判断结果: {comparison}")


def ocr_process(frame):
    global last_numbers
    # 图像预处理
    gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
    _, binary = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY_INV)

    # OCR识别
    custom_config = r'--oem 3 --psm 6 outputbase digits -c tessedit_char_whitelist=0123456789?'
    result = pytesseract.image_to_string(binary, config=custom_config)

    # 按问号分割识别结果
    parts = result.split('?')

    # 提取数字并处理
    numbers = [int(''.join(filter(str.isdigit, part))) for part in parts if ''.join(filter(str.isdigit, part))]

    # 进行比较并绘制符号
    if len(numbers) == 2:
        with lock:  # 确保对共享资源的安全访问
            if numbers != last_numbers:  # 只有当新数字不同于上一个数字时才进行绘制
                if numbers[0] > numbers[1]:
                    comparison = ">"
                    draw_symbol_with_mouse(">", (300, 1100))
                elif numbers[0] < numbers[1]:
                    comparison = "<"
                    draw_symbol_with_mouse("<",  (300, 1100))
                else:
                    comparison = "="
                last_numbers = numbers
                print_thread = Thread(target=print_result, args=(numbers, comparison))
                print_thread.start()


def capture_process():
    with mss.mss() as sct:
        while True:
            img = sct.grab(current_monitor)
            img_np = np.array(img)
            img_bgr = cv2.cvtColor(img_np, cv2.COLOR_BGRA2BGR)
            ocr_process(img_bgr)


capture_thread = Thread(target=capture_process)
capture_thread.start()

辅助代码(辅助获取屏幕坐标,用于ocr识别区域的设置):

import pyautogui
import time
#
#
#   本代码用来辅助获取屏幕定位
#
#
print("将鼠标移动到你想要的位置...")
time.sleep(3)  # 给你3秒钟的时间来移动鼠标
x, y = pyautogui.position()  # 获取鼠标当前的位置
print(f"当前鼠标坐标: ({x}, {y})")

效果图(不优化真的慢,一般人的速度):


二.抓包改包

原理:mitmproxy作为中间代理修改响应包。

缺点:配置环境较难,需要解决ssl pinnning问题,解决办法看我的另一篇文章 绕过ssl pinning,需要设置代理。本来没加密时,PK时也能用,加密后之能在练习场用了。

优点:快,可修改答案,题数等。

使用教程:安装必须的库,模拟器端使用代理

查看本机地址的方法,在cmd中输入ipconfig,找到ipv4地址,在模拟器上填入。

在python的终端输入mitmweb -s xyks.py,后面改成你文件的名字。

必须先解决ssl pinning,不然一抓包就断网,必须先解决证书验证。

我这里把答案改成了1,可以自行修改,自己分析一下json。

{
    "addErrorCount": "",
    "bestRecordQuestionCnt": 0,
    "correctCnt": 0,
    "correctRate": 0,
    "correctRateRank": 0,
    "costTime": 0,
    "encourage": null,
    "errorBookFlag": 0,
    "id": 0,
    "idString": "1295459193054003200",
    "inspirationSection": {
        "a": 42954,
        "b": 29708,
        "c": 18628,
        "d": 3010
    },
    "keypoint": "分数的乘除混合运算",
    "keypointId": 411,
    "orionKeypointId": 0,
    "practiceCntFlag": 0,
    "questionCnt": 10,
    "questions": [
        {
            "answer": "\\frac{1}{9}",
            "answers": [
                "\\frac{1}{9}"
            ],
            "content": "\\frac{9}{56}\\times(\\frac{8}{3}\\div\\frac{27}{7})=\\square",
            "costTime": 0,
            "errorState": 0,
            "id": 1,
            "script": null,
            "status": 0,
            "userAnswer": null,
            "wrongScript": null
        },
        {
            "answer": "\\frac{8}{63}",
            "answers": [
                "\\frac{8}{63}"
            ],
            "content": "\\frac{20}{21}\\div(\\frac{9}{2}\\div\\frac{3}{5})=\\square",
            "costTime": 0,
            "errorState": 0,
            "id": 1,
            "script": null,
            "status": 0,
            "userAnswer": null,
            "wrongScript": null
        },
        {
            "answer": "\\frac{24}{49}",
            "answers": [
                "\\frac{24}{49}"
            ],
            "content": "\\frac{16}{21}\\div\\frac{1}{3}\\times\\frac{3}{14}=\\square",
            "costTime": 0,
            "errorState": 0,
            "id": 1,
            "script": null,
            "status": 0,
            "userAnswer": null,
            "wrongScript": null
        },
        {
            "answer": "\\frac{5}{16}",
            "answers": [
                "\\frac{5}{16}",
                "0.3125"
            ],
            "content": "\\frac{5}{18}\\times(\\frac{5}{8}\\div\\frac{5}{9})=\\square",
            "costTime": 0,
            "errorState": 0,
            "id": 1,
            "script": null,
            "status": 0,
            "userAnswer": null,
            "wrongScript": null
        },
        {
            "answer": "\\frac{6}{7}",
            "answers": [
                "\\frac{6}{7}"
            ],
            "content": "\\frac{27}{4}\\times(\\frac{4}{7}\\div\\frac{9}{2})=\\square",
            "costTime": 0,
            "errorState": 0,
            "id": 1,
            "script": null,
            "status": 0,
            "userAnswer": null,
            "wrongScript": null
        },
        {
            "answer": "\\frac{5}{32}",
            "answers": [
                "\\frac{5}{32}",
                "0.15625"
            ],
            "content": "\\frac{25}{16}\\times\\frac{3}{4}\\div\\frac{15}{2}=\\square",
            "costTime": 0,
            "errorState": 0,
            "id": 1,
            "script": null,
            "status": 0,
            "userAnswer": null,
            "wrongScript": null
        },
        {
            "answer": "\\frac{27}{10}",
            "answers": [
                "\\frac{27}{10}",
                "2\\frac{7}{10}",
                "2.7"
            ],
            "content": "\\frac{12}{25}\\div\\frac{2}{9}\\times\\frac{5}{4}=\\square",
            "costTime": 0,
            "errorState": 0,
            "id": 1,
            "script": null,
            "status": 0,
            "userAnswer": null,
            "wrongScript": null
        },
        {
            "answer": "\\frac{28}{5}",
            "answers": [
                "\\frac{28}{5}",
                "5\\frac{3}{5}",
                "5.6"
            ],
            "content": "\\frac{35}{8}\\times(\\frac{8}{5}\\div\\frac{5}{4})=\\square",
            "costTime": 0,
            "errorState": 0,
            "id": 1,
            "script": null,
            "status": 0,
            "userAnswer": null,
            "wrongScript": null
        },
        {
            "answer": "\\frac{32}{35}",
            "answers": [
                "\\frac{32}{35}"
            ],
            "content": "\\frac{16}{45}\\div(\\frac{1}{8}\\div\\frac{9}{28})=\\square",
            "costTime": 0,
            "errorState": 0,
            "id": 1,
            "script": null,
            "status": 0,
            "userAnswer": null,
            "wrongScript": null
        },
        {
            "answer": "\\frac{9}{28}",
            "answers": [
                "\\frac{9}{28}"
            ],
            "content": "\\frac{25}{16}\\div(\\frac{5}{9}\\div\\frac{4}{35})=\\square",
            "costTime": 0,
            "errorState": 0,
            "id": 1,
            "script": null,
            "status": 0,
            "userAnswer": null,
            "wrongScript": null
        }
    ],
    "rankFlag": 0,
    "ruleType": 0,
    "shareable": true,
    "source": 0,
    "speedRank": 0,
    "trialExamId": "",
    "updatedTime": 0
}

代码:

import mitmproxy
import json
import mitmproxy.test
from mitmproxy import http


class Kousuan:
    def request(self, flow: http.HTTPFlow):
        request = flow.request

    def response(self, flow):
        response = flow.response
        request = flow.request
        if "https://xyks.yuanfudao.com/leo-math/android/exams?" in request.url:
            data = response.json()

            for i in data["questions"]:
                i["answer"] = "1"         #修改的答案,可以任意改,上下两个都改        
                i["answers"] = ["1"]

            response.set_text(json.dumps(data))


addons = [Kousuan()]

效果图:


三.frida

原理:自己查。

优点:超级快,可修改PK场的数据。

缺点:环境配置难,不适合新手,需要懂adb,frida,安卓逆向等,frida的安装也比较难,不会的看看我的另一篇文章 frida的安装

使用教程:模拟器段启动frida-server,不会的上面有教程,pc端启动代码。

代码:https://gitee.com/xiamuceer/little-ape-arithmetic自己去下。

效果图:

仅供学习!!!!!!!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值