Go 实践项目02——在线词典 | 青训营笔记

123 阅读3分钟

2 在线词典

调用第三方API查询单词翻译

使用go语言发送HTTP请求,解析json

2.1 抓包

彩云科技在线翻译:fanyi.caiyunapp.com

在网络——>dict——>右键——>复制——>复制为cURL(bash)

curl 是常用的命令行工具,用来请求 Web 服务器。它的名字就是客户端(client)的 URL 工具的意思。

cURL(客户端URL)是一个开放源代码的命令行工具,也是一个跨平台的库(libcurl),用于在服务器之间传输数据,并分发给几乎所有新的操作系统。

cURL编程用于需要通过Internet协议发送或接收数据的几乎任何地方。

  
  curl 'https://api.interpreter.caiyunai.com/v1/dict' \
    -H 'authority: api.interpreter.caiyunai.com' \
    -H 'accept: application/json, text/plain, */*' \
    -H 'accept-language: zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,ja;q=0.6,en-US;q=0.5' \
    -H 'app-name: xy' \
    -H 'content-type: application/json;charset=UTF-8' \
    -H 'device-id: 2d1d90c19f0287edbd5a561fceaea093' \
    -H 'origin: https://fanyi.caiyunapp.com' \
    -H 'os-type: web' \
    -H 'os-version;' \
    -H 'referer: https://fanyi.caiyunapp.com/' \
    -H 'sec-ch-ua: "Microsoft Edge";v="113", "Chromium";v="113", "Not-A.Brand";v="24"' \
    -H 'sec-ch-ua-mobile: ?0' \
    -H 'sec-ch-ua-platform: "Windows"' \
    -H 'sec-fetch-dest: empty' \
    -H 'sec-fetch-mode: cors' \
    -H 'sec-fetch-site: cross-site' \
    -H 'user-agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/113.0.0.0 Safari/537.36 Edg/113.0.1774.50' \
    -H 'x-authorization: token:qgemv4jr1y38jyq6vhvi' \
    --data-raw '{"trans_type":"en2zh","source":"good"}' \
    --compressed

2.2 代码生成

代码生成网址:curlconverter.com/#go

  
  package main
  ​
  import (
      "fmt"
      "io"
      "log"
      "net/http"
      "strings"
  )
  ​
  func main() {
      client := &http.Client{}
      var data = strings.NewReader(`{"trans_type":"en2zh","source":"good"}`)
      req, err := http.NewRequest("POST", "https://api.interpreter.caiyunai.com/v1/dict", data)
      if err != nil {
          log.Fatal(err)
      }
      req.Header.Set("authority", "api.interpreter.caiyunai.com")
      req.Header.Set("accept", "application/json, text/plain, */*")
      req.Header.Set("accept-language", "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,ja;q=0.6,en-US;q=0.5")
      req.Header.Set("app-name", "xy")
      req.Header.Set("content-type", "application/json;charset=UTF-8")
      req.Header.Set("device-id", "2d1d90c19f0287edbd5a561fceaea093")
      req.Header.Set("origin", "https://fanyi.caiyunapp.com")
      req.Header.Set("os-type", "web")
      req.Header.Set("os-version", "")
      req.Header.Set("referer", "https://fanyi.caiyunapp.com/")
      req.Header.Set("sec-ch-ua", `"Microsoft Edge";v="113", "Chromium";v="113", "Not-A.Brand";v="24"`)
      req.Header.Set("sec-ch-ua-mobile", "?0")
      req.Header.Set("sec-ch-ua-platform", `"Windows"`)
      req.Header.Set("sec-fetch-dest", "empty")
      req.Header.Set("sec-fetch-mode", "cors")
      req.Header.Set("sec-fetch-site", "cross-site")
      req.Header.Set("user-agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/113.0.0.0 Safari/537.36 Edg/113.0.1774.50")
      req.Header.Set("x-authorization", "token:qgemv4jr1y38jyq6vhvi")
      resp, err := client.Do(req)
      if err != nil {
          log.Fatal(err)
      }
      defer resp.Body.Close()
      bodyText, err := io.ReadAll(resp.Body)
      if err != nil {
          log.Fatal(err)
      }
      fmt.Printf("%s\n", bodyText)
  }

2.3 生成request body

将结构体初始化后,调用JSON.marshaler得到序列化后的字符串(字节数组)

使用bytes.NewReader()获得data

2.4 解析response body

将json字符串转为对应的结构体:oktools.net/json2go

  
  type AutoGenerated struct {
      Rc int `json:"rc"`
      Wiki struct {
      } `json:"wiki"`
      Dictionary struct {
          Prons struct {
              EnUs string `json:"en-us"`
              En string `json:"en"`
          } `json:"prons"`
          Explanations []string `json:"explanations"`
          Synonym []string `json:"synonym"`
          Antonym []string `json:"antonym"`
          WqxExample [][]string `json:"wqx_example"`
          Entry string `json:"entry"`
          Type string `json:"type"`
          Related []interface{} `json:"related"`
          Source string `json:"source"`
      } `json:"dictionary"`
  }

2.5 打印结果

  fmt.Println(word,"UK:",dictResponse.Dictionary.Prons.En,"US:",dictResponse.Dictionary.Prons.EnUs)
  for _,item := range dictResponse.Dictionary.Explanations{
      fmt.Println(item)
  }

2.6 运行

1684678175168.png

2.7 代码

  
  package main
  ​
  import (
      "bytes"
      "encoding/json"
      "fmt"
      "io"
      "log"
      "net/http"
      //"os"
      "strings"
  )
  ​
  type DictRequest struct{
      TransType string `json:"trans_type"`
      Source string `json:"source"`
      UserId string `json:"user_id"`
  }
  type DictResponse struct {
      Rc int `json:"rc"`
      Wiki struct {
      } `json:"wiki"`
      Dictionary struct {
          Prons struct {
              EnUs string `json:"en-us"`
              En string `json:"en"`
          } `json:"prons"`
          Explanations []string `json:"explanations"`
          Synonym []string `json:"synonym"`
          Antonym []interface{} `json:"antonym"`
          WqxExample [][]string `json:"wqx_example"`
          Entry string `json:"entry"`
          Type string `json:"type"`
          Related []interface{} `json:"related"`
          Source string `json:"source"`
      } `json:"dictionary"`
  }
  ​
  func query(word string){
      client := &http.Client{}
      request := DictRequest{TransType: "en2zh",Source: word}
      buf, err := json.Marshal(request)
      if err != nil{
          log.Fatal(err)
      }
      var data = bytes.NewReader(buf)
      req, err := http.NewRequest("POST", "https://api.interpreter.caiyunai.com/v1/dict", data) // 创建请求,data是只读流
      if err != nil {
          log.Fatal(err)
      }
      req.Header.Set("authority", "api.interpreter.caiyunai.com") // 设置请求头
      req.Header.Set("accept", "application/json, text/plain, */*")
      req.Header.Set("accept-language", "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,ja;q=0.6,en-US;q=0.5")
      req.Header.Set("app-name", "xy")
      req.Header.Set("content-type", "application/json;charset=UTF-8")
      req.Header.Set("device-id", "1cd4889aebd2e8e18092825ec1af5743")
      req.Header.Set("origin", "https://fanyi.caiyunapp.com")
      req.Header.Set("os-type", "web")
      req.Header.Set("os-version", "")
      req.Header.Set("referer", "https://fanyi.caiyunapp.com/")
      req.Header.Set("sec-ch-ua", `"Microsoft Edge";v="113", "Chromium";v="113", "Not-A.Brand";v="24"`)
      req.Header.Set("sec-ch-ua-mobile", "?0")
      req.Header.Set("sec-ch-ua-platform", `"Windows"`)
      req.Header.Set("sec-fetch-dest", "empty")
      req.Header.Set("sec-fetch-mode", "cors")
      req.Header.Set("sec-fetch-site", "cross-site")
      req.Header.Set("user-agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/113.0.0.0 Safari/537.36 Edg/113.0.1774.42")
      req.Header.Set("x-authorization", "token:qgemv4jr1y38jyq6vhvi")
      resp, err := client.Do(req) // 发起请求
      if err != nil {
          log.Fatal(err)
      }
      defer resp.Body.Close() // 避免资源泄露,defer手动关闭流,会在函数结束之后运行
      bodyText, err := io.ReadAll(resp.Body) // 读取响应
      if err != nil {
          log.Fatal(err)
      }
      if resp.StatusCode != 200{
          log.Fatal("bad StatusCode:",resp.StatusCode,"body",string(bodyText)) // 错误的状态码,如404
      }
      var dictResponse DictResponse
      err = json.Unmarshal(bodyText,&dictResponse)
      if err != nil{
          log.Fatal(err)
      }
      fmt.Println(word,"UK:",dictResponse.Dictionary.Prons.En,"US:",dictResponse.Dictionary.Prons.EnUs)
      for _,item := range dictResponse.Dictionary.Explanations{
          fmt.Println(item)
      }
  }
  ​
  func main() {
      // 在命令行go run后输入查询单词
      /* if len(os.Args) != 2{
          fmt.Fprintf(os.Stderr,`usage:simpleDict WORD example: simpleDict hello`)
          os.Exit(1)
      }
      word := os.Args[1] */
      var word string
      for{
          fmt.Print("\n请输入要查询的单词(输入0结束):")
          _, err := fmt.Scanf("%v\n", &word)
          if err != nil{
              fmt.Println("读取输入出现错误,请重试!",err)
              continue
          }
          word = strings.Trim(strings.TrimSuffix(word, "\n"), "\r")
          if word=="0"{
              break
          }
          query(word)
      }
  }
  ​