client.go 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113
  1. // Package ocr 提供验证码识别服务。
  2. //
  3. // TODO: 迁移到 common/clients/ocr.go
  4. package ocr
  5. import (
  6. "context"
  7. "encoding/json"
  8. "io"
  9. "net/http"
  10. "net/url"
  11. "strings"
  12. "git.listensoft.net/tool/jspkit/logger"
  13. "go.uber.org/zap"
  14. )
  15. // DefaultOcrOption 是默认的验证码识别服务配置
  16. var DefaultOcrOption = OcrOption{
  17. User: user,
  18. Pass: pass,
  19. SoftId: softid,
  20. }
  21. const DefaultOcrURL = "http://upload.chaojiying.net"
  22. // OcrOption 是验证码识别服务的配置
  23. type OcrOption struct {
  24. User string
  25. Pass string
  26. SoftId string
  27. }
  28. // NewDefaultOcrClient 使用默认参数创建客户端
  29. func NewDefaultOcrClient() OcrClient {
  30. return OcrClient{
  31. Option: DefaultOcrOption,
  32. Client: http.DefaultClient,
  33. Logger: logger.GetLogger(),
  34. BaseURL: DefaultOcrURL,
  35. }
  36. }
  37. // OcrClient 是超级鹰验证码识别接口客户端。
  38. // 文档链接: https://www.chaojiying.com/api-5.html
  39. type OcrClient struct {
  40. Option OcrOption // 接口授权相关
  41. Client *http.Client // HTTP 客户端
  42. Logger *zap.Logger // 日志
  43. BaseURL string // 服务地址
  44. }
  45. // 验证码识别,传入图片路径。
  46. func (c OcrClient) GetCaptchaCodePath(ctx context.Context, imgPath string) (string, error) {
  47. bstr, err := base64Img(imgPath)
  48. if err != nil {
  49. return "", err
  50. }
  51. return c.GetCaptchaCode(ctx, bstr)
  52. }
  53. // 验证码识别,传入 "data:image/jpg;base64,xxx" 格式的 url。
  54. // 该 url 一般为 img 标签的 src 属性。不校验传入的 url 是否合法。
  55. func (c OcrClient) GetCaptchaCodeURL(ctx context.Context, b64 string) (string, error) {
  56. _, bstr, _ := strings.Cut(b64, ",")
  57. return c.GetCaptchaCode(ctx, bstr)
  58. }
  59. // 验证码识别,传入 base64 编码的图片。
  60. // 文档链接: https://www.chaojiying.com/price.html
  61. func (c OcrClient) GetCaptchaCode(ctx context.Context, bstr string) (string, error) {
  62. u, err := url.Parse(c.BaseURL)
  63. if err != nil {
  64. return "", err
  65. }
  66. u = u.JoinPath("/Upload/Processing.php")
  67. param := make(url.Values)
  68. param.Set("user", c.Option.User)
  69. param.Set("pass", c.Option.Pass)
  70. param.Set("softid", c.Option.SoftId)
  71. param.Set("codetype", "1902")
  72. param.Set("file_base64", bstr)
  73. params := param.Encode()
  74. req, err := http.NewRequestWithContext(ctx, http.MethodPost, u.String(), strings.NewReader(params))
  75. if err != nil {
  76. return "", err
  77. }
  78. req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
  79. resp, err := c.Client.Do(req)
  80. if err != nil {
  81. return "", err
  82. }
  83. defer resp.Body.Close()
  84. body, err := io.ReadAll(resp.Body)
  85. if err != nil {
  86. return "", err
  87. }
  88. var rs Result
  89. err = json.Unmarshal(body, &rs)
  90. if err != nil {
  91. return "", err
  92. }
  93. if rs.ErrNo != 0 {
  94. c.Logger.Error("识别报错", zap.ByteString("body", body))
  95. return "", err
  96. }
  97. c.Logger.Debug("识别结果", zap.String("picStr", rs.PicStr))
  98. return rs.PicStr, nil
  99. }