// Package ocr 提供验证码识别服务。 // // TODO: 迁移到 common/clients/ocr.go package ocr import ( "context" "encoding/json" "io" "net/http" "net/url" "strings" "git.listensoft.net/tool/jspkit/logger" "go.uber.org/zap" ) // DefaultOcrOption 是默认的验证码识别服务配置 var DefaultOcrOption = OcrOption{ User: user, Pass: pass, SoftId: softid, } const DefaultOcrURL = "http://upload.chaojiying.net" // OcrOption 是验证码识别服务的配置 type OcrOption struct { User string Pass string SoftId string } // NewDefaultOcrClient 使用默认参数创建客户端 func NewDefaultOcrClient() OcrClient { return OcrClient{ Option: DefaultOcrOption, Client: http.DefaultClient, Logger: logger.GetLogger(), BaseURL: DefaultOcrURL, } } // OcrClient 是超级鹰验证码识别接口客户端。 // 文档链接: https://www.chaojiying.com/api-5.html type OcrClient struct { Option OcrOption // 接口授权相关 Client *http.Client // HTTP 客户端 Logger *zap.Logger // 日志 BaseURL string // 服务地址 } // 验证码识别,传入图片路径。 func (c OcrClient) GetCaptchaCodePath(ctx context.Context, imgPath string) (string, error) { bstr, err := base64Img(imgPath) if err != nil { return "", err } return c.GetCaptchaCode(ctx, bstr) } // 验证码识别,传入 "data:image/jpg;base64,xxx" 格式的 url。 // 该 url 一般为 img 标签的 src 属性。不校验传入的 url 是否合法。 func (c OcrClient) GetCaptchaCodeURL(ctx context.Context, b64 string) (string, error) { _, bstr, _ := strings.Cut(b64, ",") return c.GetCaptchaCode(ctx, bstr) } // 验证码识别,传入 base64 编码的图片。 // 文档链接: https://www.chaojiying.com/price.html func (c OcrClient) GetCaptchaCode(ctx context.Context, bstr string) (string, error) { u, err := url.Parse(c.BaseURL) if err != nil { return "", err } u = u.JoinPath("/Upload/Processing.php") param := make(url.Values) param.Set("user", c.Option.User) param.Set("pass", c.Option.Pass) param.Set("softid", c.Option.SoftId) param.Set("codetype", "1902") param.Set("file_base64", bstr) params := param.Encode() req, err := http.NewRequestWithContext(ctx, http.MethodPost, u.String(), strings.NewReader(params)) if err != nil { return "", err } req.Header.Add("Content-Type", "application/x-www-form-urlencoded") resp, err := c.Client.Do(req) if err != nil { return "", err } defer resp.Body.Close() body, err := io.ReadAll(resp.Body) if err != nil { return "", err } var rs Result err = json.Unmarshal(body, &rs) if err != nil { return "", err } if rs.ErrNo != 0 { c.Logger.Error("识别报错", zap.ByteString("body", body)) return "", err } c.Logger.Debug("识别结果", zap.String("picStr", rs.PicStr)) return rs.PicStr, nil }