与之前的方案类似,这次使用了Umi-OCR,当前的最新版本支持HTTP服务,占用资源也不多。可惜一点的是它是一个GUI应用。
直接附上代码,原理就是:1.adb手机截图 2.OCR识别 3.判断付费(这段代码没有)
package main
import (
"bytes"
"encoding/base64"
"encoding/json"
"fmt"
"io"
"net/http"
"os"
"os/exec"
"time"
)
// OCR请求结构体
type OCRRequest struct {
Base64 string `json:"base64"`
Options map[string]string `json:"options,omitempty"`
}
func main() {
// 1. 通过ADB截取屏幕
imagePath, err := captureScreen()
if err != nil {
panic(fmt.Sprintf("截图失败: %v", err))
}
defer os.Remove(imagePath) // 清理临时文件
// 2. 读取图片并编码为Base64
base64Str, err := imageToBase64(imagePath)
if err != nil {
panic(fmt.Sprintf("Base64编码失败: %v", err))
}
// 3. 构造请求体
reqData := OCRRequest{
Base64: base64Str,
Options: map[string]string{
"data.format": "text",
},
}
// 4. 发送HTTP请求
url := "http://127.0.0.1:1224/api/ocr"
resp, err := sendOCRRequest(url, reqData)
if err != nil {
panic(fmt.Sprintf("API请求失败: %v", err))
}
fmt.Printf("识别结果: %+v\n", resp)
}
// ADB截图实现(需确保adb在PATH中)
func captureScreen() (string, error) {
timestamp := time.Now().Format("20060102_150405")
remotePath := fmt.Sprintf("/sdcard/screenshot_%s.png", timestamp)
localPath := fmt.Sprintf("screenshot_%s.png", timestamp)
// 执行截图命令
cmd := exec.Command("adb", "shell", "screencap", "-p", remotePath)
if err := cmd.Run(); err != nil {
return "", fmt.Errorf("执行ADB截图命令失败: %v", err)
}
// 拉取截图到本地
cmd = exec.Command("adb", "pull", remotePath, localPath)
if err := cmd.Run(); err != nil {
return "", fmt.Errorf("拉取截图文件失败: %v", err)
}
// 清理设备端文件
exec.Command("adb", "shell", "rm", remotePath).Run()
return localPath, nil
}
// 图片转Base64(不包含Data URI前缀)
func imageToBase64(path string) (string, error) {
file, err := os.Open(path)
if err != nil {
return "", err
}
defer file.Close()
bytes, err := io.ReadAll(file)
if err != nil {
return "", err
}
return base64.StdEncoding.EncodeToString(bytes), nil
}
// 定义API响应结构体(仅保留data字段)
type OCRResponse struct {
Data interface{} `json:"data"` // 根据实际API返回结构定义具体类型
}
// 发送OCR请求(支持自定义选项)
func sendOCRRequest(url string, reqData OCRRequest) (interface{}, error) {
jsonData, err := json.Marshal(reqData)
if err != nil {
return nil, fmt.Errorf("JSON序列化失败: %v", err)
}
resp, err := http.Post(url, "application/json", bytes.NewReader(jsonData))
if err != nil {
return nil, fmt.Errorf("HTTP请求失败: %v", err)
}
defer resp.Body.Close()
// 仅解析data字段
var response struct {
Data interface{} `json:"data"`
}
if err := json.NewDecoder(resp.Body).Decode(&response); err != nil {
return nil, fmt.Errorf("JSON解析失败: %v", err)
}
return response.Data, nil
}