前言:当前许多教程都建议在电脑上下载模拟器并运行小猿搜题进行操作。然而,本文将介绍如何直接通过电脑连接手机,实现快速解题,无需在电脑上下载模拟器。
脚本的速度远远比不上抓包的速度,如果使用抓包甚至可以做到0秒,但是相信可以给您写手机软件的脚本提供一些思路,说不定以后可以开发一个抢票脚本hh。
一、安装编译器
1. 安装 Python
首先,你需要确保已经安装了 Python。如果没有安装,可以前往 Python 官网 下载并安装适合你操作系统的版本。建议安装 Python 3.6 或更高版本。
python --version
2. 创建虚拟环境(可选,萌新就不用创建虚拟环境了)
为了避免库冲突,建议为这个项目创建一个 Python 虚拟环境:
python -m venv env
source env/bin/activate # Linux 或 Mac
env\Scripts\activate # Windows
二、(最重要的工具) ADB(Android Debug Bridge)
ADB 是与 Android 设备通信的桥梁,用于捕获屏幕截图和模拟手势操作。ADB 不属于 Python 库,但你需要在电脑上安装它。
-
安装 ADB:
- 在 Android 开发者工具官网 下载并安装 ADB。
- 解压后,将
platform-tools
目录添加到系统的PATH
环境变量中。
-
验证 ADB 是否安装成功:
-
adb version
三、配置 ADB 与手机连接
1. 启用手机上的开发者选项与 USB 调试
- 在 Android 手机上,进入 设置 > 关于手机 > 连续点击 版本号(Build Number)7 次以启用开发者模式。
- 启用开发者选项后,进入 设置 > 开发者选项,开启 USB 调试。
2. 连接手机与 ADB
-
使用 USB 数据线连接手机到电脑。
-
在命令行中使用以下命令检查是否成功连接:
连接手机,检查设备是否被识别:(连接时可能会出现一些问题,具体的连接操作,可以期待一下我的下一篇教程)
adb devices
3. 截取手机屏幕
通过 ADB 命令截取手机屏幕并将图片保存到电脑:(验证一下是否连接并正确授权)
adb exec-out screencap -p > screen.png
4. 模拟手势操作(小小的测试一下是否正确,可以不做)
使用 ADB 模拟手势操作,比如通过 swipe
命令在屏幕上绘制符号:
adb shell input swipe 500 1500 800 1600 # 模拟从坐标 (500,1500) 到 (800,1600) 的滑动
如果设备状态显示 unauthorized
,需要在手机上确认调试授权提示,点击 允许 或 始终允许。
(如果还出现别的连接错误,可以在评论区说出来,我尽量给大家改哈,博主也是萌新hhh)
四、安装必要的 Python 库(因为所有的库我早就安装过了,可能会有遗漏,如有遗漏欢迎指正)
以下是项目中会使用的关键 Python 库,它们涵盖了图像处理、OCR 识别和自动化操作。
1.Pillow(PIL):用于图像处理和裁剪
Pillow 是 Python 的图像处理库,能够处理和修改截图,包括裁剪需要识别的数字区域。
- 安装 Pillow:
-
pip install pillow
2.PyAutoGUI(可选):用于模拟屏幕操作
PyAutoGUI 是一个 Python 库,用于自动化鼠标和键盘的操作。虽然我们主要使用 ADB 进行手势模拟,但 PyAutoGUI 也是一种选择,尤其是在桌面应用中进行自动化操作时。如果你还想使用模拟器在电脑上刷,这个库是必须的
- 安装 PyAutoGUI:
-
pip install pyautogui
3.Tesseract OCR:用于图像文字识别
Tesseract 是一个开源的 OCR(光学字符识别)引擎,支持识别图像中的文字。在脚本中主要用来识别数字。
Tesseract 的安装步骤:
-
安装 Tesseract 引擎
- Windows:你可以通过Tesseract 的 GitHub 页面下载适用于 Windows 的安装包,安装后将安装路径添加到系统
PATH
。 - Mac:可以通过 Homebrew 进行安装:
brew install tesseract
- Linux:通过包管理器安装(如 Ubuntu):
sudo apt-get install tesseract-ocr
- Windows:你可以通过Tesseract 的 GitHub 页面下载适用于 Windows 的安装包,安装后将安装路径添加到系统
配置 Tesseract 路径(仅适用于 Windows): 如果你使用的是 Windows,需要在 Python 脚本中指定 Tesseract 可执行文件的路径: (当然你也可以配置到系统路径当中,这样就不用在代码中指定路径,我比较推荐这一种)
import pytesseract
pytesseract.pytesseract.tesseract_cmd = r'C:\Program Files\Tesseract-OCR\tesseract.exe'
//代码在记得在最后添加到你的程序当中,路径修改为你下载到的位置
到这一步就恭喜您已经完成了所有的配置过程!!!接下来我们开始说代码
五、代码解析
1.导入的库:(用法相信大家都明白,不做赘述了)
- os:用于与操作系统交互。这里主要用来执行 ADB 命令与 Android 设备进行通信。
- time:用于处理时间相关操作,如设置等待时间。你使用它来控制流程中的延迟。
- re:正则表达式模块,用于处理和过滤字符串。你使用它来过滤 OCR 识别出的结果,确保只保留数字字符。
- PIL (Pillow):Python 图像处理库。
Image
用于打开和裁剪图片,ImageEnhance
用于增强图像对比度以提高 OCR 识别的准确性。 - pytesseract:Tesseract OCR 的 Python 接口,用于从图像中提取文本或数字。
- ThreadPoolExecutor:用于并行执行任务。在你的代码中,
ThreadPoolExecutor
被用来并行处理左右两个数字的 OCR 识别,以提高性能。
import os
import time
import re
from PIL import Image, ImageEnhance
import pytesseract
from concurrent.futures import ThreadPoolExecutor
2.定义 ADB 命令执行函数
def run_adb_command(command):
os.system(f"adb {command}")
- 作用:执行 ADB 命令。这是一个通用的函数,使用
os.system
来运行命令行中的 ADB 命令。 - 示例:通过
adb exec-out screencap -p
获取截图,或通过adb shell input swipe
模拟手势操作。
3. 截取屏幕并保存截图
def capture_screen(filename="screen.png"):
run_adb_command(f"exec-out screencap -p > {filename}")
- 作用:通过 ADB 命令截取 Android 设备当前屏幕并将其保存为本地图片文件。
- 细节:
adb exec-out screencap -p
是 ADB 用于截图的命令,-p
生成 PNG 格式,> {filename}
表示将截图保存为文件。- 默认文件名为
screen.png
。
4. 裁剪图片,分别得到左侧和右侧的数字区域
def crop_numbers(img_path):
img = Image.open(img_path)
# 左侧数字区域
left_coords = (240, 611, 422, 795)
left_number_img = img.crop(left_coords)
left_number_img.save('left_number.png')
# 右侧数字区域
right_coords = (667, 624, 864, 788)
right_number_img = img.crop(right_coords)
right_number_img.save('right_number.png')
- 作用:使用 Pillow 裁剪屏幕截图中左右两侧的数字区域,将其保存为两个独立的图片文件,供后续 OCR 使用。剪裁的区域划分小一点识别的会更加精准
- (裁剪的位置参数是根据我的手机分辨率和小猿口算出现数字的位置剪裁的)
- (我估计手机的裁剪区域都差不多,如果你没有裁剪到图片,可能还需要自己去确定一下自己手机的裁剪区域,怎么查看手机某一点的坐标可以期待一下我的下一篇教程)
- 细节:
img.crop(left_coords)
:根据坐标(240, 611, 422, 795)
裁剪出左侧数字区域。img.crop(right_coords)
:根据坐标(667, 624, 864, 788)
裁剪出右侧数字区域。left_number_img.save('left_number.png')
将裁剪出的左侧数字图像保存为left_number.png
。
5. 使用 Tesseract OCR 识别图片中的数字
def recognize_number(image_path):
img = Image.open(image_path)
# 转换为灰度图像
gray_img = img.convert('L')
# 增强对比度
enhancer = ImageEnhance.Contrast(gray_img)
enhanced_img = enhancer.enhance(3.0)
# 二值化处理
bw_img = enhanced_img.point(lambda x: 0 if x < 150 else 255, '1')
# 使用 OCR 识别数字
text = pytesseract.image_to_string(bw_img, config='--psm 7').strip()
print(f"OCR 识别结果: {text}")
# 过滤掉非数字字符,确保只识别数字
filtered_text = re.sub(r'[^0-9]', '', text)
if filtered_text.isdigit():
return int(filtered_text)
else:
print(f"无法识别有效数字:{text}")
return None
6. 并行处理左右数字的 OCR
def recognize_both_numbers():
with ThreadPoolExecutor() as executor:
left_future = executor.submit(recognize_number, 'left_number.png')
right_future = executor.submit(recognize_number, 'right_number.png')
left_number = left_future.result()
right_number = right_future.result()
return left_number, right_number
7. 比较两个数字,返回相应的符号
def compare_numbers(left, right):
if left is None or right is None:
return None
if left > right:
return '>'
elif left < right:
return '<'
else:
return '='
8. 模拟屏幕滑动(手写符号)
def swipe(start_x, start_y, end_x, end_y, duration=100):
os.system(f"adb shell input swipe {start_x} {start_y} {end_x} {end_y} {duration}")
9. 根据比大小结果手写相应符号
def write_symbol(symbol):
if symbol == '>':
swipe(281, 1470, 543, 1595) # 大于号上半部分
swipe(543, 1595, 281, 1720) # 大于号下半部分
elif symbol == '<':
swipe(683, 1409, 312, 1615) # 小于号上半部分
swipe(312, 1615, 683, 1724) # 小于号下半部分
elif symbol == '=':
swipe(305, 1473, 666, 1473) # 等于号第一条横线
swipe(305, 1709, 666, 1709) # 等于号第二条横线
符号是我自己徒手画的,然后定位到起点终点的位置。
10.主函数
def main():
while True:
capture_screen()
crop_numbers('screen.png
六、完整代码
import os
import time
import re
from PIL import Image, ImageEnhance
import pytesseract
from concurrent.futures import ThreadPoolExecutor
# 定义adb命令执行函数
def run_adb_command(command):
os.system(f"adb {command}")
# 截取屏幕并保存截图
def capture_screen(filename="screen.png"):
run_adb_command(f"exec-out screencap -p > {filename}")
# 裁剪图片,分别得到左侧和右侧的数字区域
def crop_numbers(img_path):
img = Image.open(img_path)
# 左侧数字区域 (使用你提供的坐标)
left_coords = (240, 611, 422, 795) # 左侧数字的区域坐标
left_number_img = img.crop(left_coords)
left_number_img.save('left_number.png')
# 右侧数字区域 (使用你提供的坐标)
right_coords = (667, 624, 864, 788) # 右侧数字的区域坐标
right_number_img = img.crop(right_coords)
right_number_img.save('right_number.png')
# 使用 Tesseract OCR 识别图片中的数字
def recognize_number(image_path):
img = Image.open(image_path)
# 转换为灰度图像
gray_img = img.convert('L')
# 增强对比度
enhancer = ImageEnhance.Contrast(gray_img)
enhanced_img = enhancer.enhance(3.0) # 进一步增强对比度
# 二值化处理 (可以调整阈值,如150或更低)
bw_img = enhanced_img.point(lambda x: 0 if x < 150 else 255, '1')
# 使用 OCR 识别数字
text = pytesseract.image_to_string(bw_img, config='--psm 7').strip()
print(f"OCR 识别结果: {text}")
# 过滤掉非数字字符,确保只识别数字
filtered_text = re.sub(r'[^0-9]', '', text)
if filtered_text.isdigit():
return int(filtered_text)
else:
print(f"无法识别有效数字:{text}")
return None
# 并行处理左右数字的 OCR
def recognize_both_numbers():
with ThreadPoolExecutor() as executor:
left_future = executor.submit(recognize_number, 'left_number.png')
right_future = executor.submit(recognize_number, 'right_number.png')
left_number = left_future.result()
right_number = right_future.result()
return left_number, right_number
# 比较两个数字,返回相应的符号
def compare_numbers(left, right):
if left is None or right is None:
return None # 如果任意一个数字未能识别,跳过比较
if left > right:
return '>'
elif left < right:
return '<'
else:
return '='
# 模拟屏幕滑动(手写符号)
def swipe(start_x, start_y, end_x, end_y, duration=100):
os.system(f"adb shell input swipe {start_x} {start_y} {end_x} {end_y} {duration}")
# 根据比大小结果手写相应符号
def write_symbol(symbol):
if symbol == '>':
swipe(281, 1470, 543, 1595) # 大于号上半部分
swipe(543, 1595, 281, 1720) # 大于号下半部分
elif symbol == '<':
swipe(683, 1409, 312, 1615) # 小于号上半部分
swipe(312, 1615, 683, 1724) # 小于号下半部分
elif symbol == '=':
swipe(305, 1473, 666, 1473) # 等于号第一条横线
swipe(305, 1709, 666, 1709) # 等于号第二条横线
# 主函数,整合整个流程
def main():
while True:
# 1. 截取屏幕
capture_screen()
# 2. 裁剪左右数字区域
crop_numbers('screen.png')
# 3. 并行处理 OCR 识别左右数字
left_number, right_number = recognize_both_numbers()
# 检查是否成功识别
if left_number is None or right_number is None:
print("无法识别数字,跳过当前题目")
time.sleep(0.1)
continue
print(f"识别到的数字: 左边={left_number}, 右边={right_number}")
# 4. 比较数字,获取符号
symbol = compare_numbers(left_number, right_number) # 比较左侧和右侧的数字
if symbol is None:
print("跳过当前题目,符号无法确定")
time.sleep(0.1)
continue
print(f"将要书写的符号: {symbol}")
# 5. 手写符号
write_symbol(symbol)
# 6. 等待自动跳转到下一题,延迟5秒以避免误操作
time.sleep(0.5)
if __name__ == "__main__":
main()