GO语言工程实践课后作业实现| 青训营

81 阅读6分钟

这是青训营笔记的第七篇文章。

在线词典

首先,我们跟随老师上课讲的,先来看—下我们要用到的API,以彩云科技提供的在线翻译为例。先请打开彩云翻译的网页彩云小译 - 在线翻译 (caiyunapp.com),然后右键检查打开浏览器的开发者工具。

1.抓包

首先点击F12进入开发者工具,在左侧文本框输入一个简单单词,我们点一下翻译按钮,浏览器会发送一系列请求,我们能很轻松地找到那个用来查询单词的请求。 image.png

找到这个 post的请求。

image.png

我们通过预览,查看该请求返回信息是否使我们想要的单词对应词条信息。

image.png

然后我们找到这个请求后,右键这个请求,选择复制为cURL(bash)

image.png

2.生成代码

需要在 Golang 里面去发送这个请求。但是这个请求比较复杂,用代码构造很麻烦。可以用一种简单的方式来生成代码,如下

然后打开一个网址,Convert curl commands to Go (curlconverter.com)把刚才复制的代码粘贴到文本框内

网页捕获_19-8-2023_155938_curlconverter.com.jpeg

获得以下代码,将这个代码粘贴到编辑器中

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("sec-ch-ua", `" Not A;Brand";v="99", "Chromium";v="8"`)
	req.Header.Set("sec-ch-ua-mobile", "?0")
	req.Header.Set("user-agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.131 Safari/537.36 SLBrowser/8.0.1.4031 SLBChan/103")
	req.Header.Set("app-name", "xy")
	req.Header.Set("content-type", "application/json;charset=UTF-8")
	req.Header.Set("accept", "application/json, text/plain, */*")
	req.Header.Set("device-id", "19d327dca1394d0846bd1495388c4a91")
	req.Header.Set("os-type", "web")
	req.Header.Set("x-authorization", "token:qgemv4jr1y38jyq6vhvi")
	req.Header.Set("origin", "https://fanyi.caiyunapp.com")
	req.Header.Set("sec-fetch-site", "cross-site")
	req.Header.Set("sec-fetch-mode", "cors")
	req.Header.Set("sec-fetch-dest", "empty")
	req.Header.Set("referer", "https://fanyi.caiyunapp.com/")
	req.Header.Set("accept-language", "zh-CN,zh;q=0.9")
	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)
}

将上述代码运行之后,我们可以得到

image-20230801181437883.png

但是之前输入是固定的,我们是要从一个变量来输入,我们需要用到JSON序列化

3.生成解析 request body

在 Golang 里面,需要生成一段 JSON ,常用的方式是先构造出来一个结构体,这个结构体和需要生成的 JSON 的结构是一一对应的。而如何操作呢,在golang中,更常用的方式是和 request 的一样,写一个结构体,把返回的 JSON 反序列化到结构体里面。但是在浏览器里面可以看到这个 API 返回的结构非常复杂,如果要一一定义结构体字段,非常繁琐并且容易出错。

我们可以利用JSON转Golang Struct - 在线工具 - OKTools来解析 response body

我们将之前网站获取的json(preview里面的)粘贴进去自动获取一个结构体,下面是我获取的json

{
    "rc": 0,
    "wiki": {},
    "dictionary": {
        "prons": {
            "en-us": "[g\u028ad]",
            "en": "[gud]"
        },
        "explanations": [
            "a.\u597d\u7684;\u5584\u826f\u7684;\u5feb\u4e50\u7684;\u771f\u6b63\u7684;\u5bbd\u5927\u7684;\u6709\u76ca\u7684;\u8001\u7ec3\u7684;\u5e78\u798f\u7684;\u5fe0\u5b9e\u7684;\u4f18\u79c0\u7684;\u5b8c\u6574\u7684;\u5f7b\u5e95\u7684;\u4e30\u5bcc\u7684",
            "n.\u5229\u76ca;\u597d\u5904;\u5584\u826f;\u597d\u4eba",
            "ad.=well"
        ],
        "synonym": [
            "excellent",
            "fine",
            "nice",
            "splendid",
            "proper"
        ],
        "antonym": [
            "bad",
            "wrong",
            "evil",
            "harmful",
            "poor"
        ],
        "wqx_example": [
            [
                "to the good",
                "\u6709\u5229,\u6709\u597d\u5904"
            ],
            [
                "good, bad and indifferent",
                "\u597d\u7684,\u574f\u7684\u548c\u4e00\u822c\u7684"
            ],
            [
                "good innings",
                "\u957f\u5bff"
            ],
            [
                "good and ...",
                "\u5f88,\u9887;\u5b8c\u5168,\u5f7b\u5e95"
            ],
            [
                "do somebody's heart good",
                "\u5bf9\u67d0\u4eba\u7684\u5fc3\u810f\u6709\u76ca,\u4f7f\u67d0\u4eba\u611f\u5230\u6109\u5feb"
            ],
            [
                "do somebody good",
                "\u5bf9\u67d0\u4eba\u6709\u76ca"
            ],
            [
                "be good for",
                "\u5bf9\u2026\u6709\u6548,\u9002\u5408,\u80dc\u4efb"
            ],
            [
                "be good at",
                "\u5728\u2026\u65b9\u9762(\u5b66\u5f97,\u505a\u5f97)\u597d;\u5584\u4e8e"
            ],
            [
                "as good as one's word",
                "\u4fe1\u5b88\u8bfa\u8a00,\u503c\u5f97\u4fe1\u8d56"
            ],
            [
                "as good as",
                "\u5b9e\u9645\u4e0a,\u51e0\u4e4e\u7b49\u4e8e"
            ],
            [
                "all well and good",
                "\u4e5f\u597d,\u8fd8\u597d,\u5f88\u4e0d\u9519"
            ],
            [
                "a good",
                "\u76f8\u5f53,\u8db3\u8db3"
            ],
            [
                "He is good at figures . ",
                "\u4ed6\u5584\u4e8e\u8ba1\u7b97\u3002"
            ]
        ],
        "entry": "good",
        "type": "word",
        "related": [],
        "source": "wenquxing"
    }
}

可以得到go里面的这样一个结构体,可以点击转换=嵌套,使这个代码更简洁化。

go
复制代码
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"`
}

获取完之后将这个相应结构体放入你的代码中,接下来我们来打印结果

先观察那个 json 可以看出需要的结果是在 Dictionary.explanations 里的,用 for range 循环来迭代它,然后直接打印结构,参照一些词典的显示方式,可以在前面打印出这个单词和它的音标。

最后放上我的代码:

package main

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"os"
)

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 []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"`
}
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)
	if err != nil {
		log.Fatal(err)
	}
	req.Header.Set("authority", "api.interpreter.caiyunai.com")
	req.Header.Set("sec-ch-ua", `" Not A;Brand";v="99", "Chromium";v="8"`)
	req.Header.Set("sec-ch-ua-mobile", "?0")
	req.Header.Set("user-agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.131 Safari/537.36 SLBrowser/8.0.1.4031 SLBChan/103")
	req.Header.Set("app-name", "xy")
	req.Header.Set("content-type", "application/json;charset=UTF-8")
	req.Header.Set("accept", "application/json, text/plain, */*")
	req.Header.Set("device-id", "19d327dca1394d0846bd1495388c4a91")
	req.Header.Set("os-type", "web")
	req.Header.Set("x-authorization", "token:qgemv4jr1y38jyq6vhvi")
	req.Header.Set("origin", "https://fanyi.caiyunapp.com")
	req.Header.Set("sec-fetch-site", "cross-site")
	req.Header.Set("sec-fetch-mode", "cors")
	req.Header.Set("sec-fetch-dest", "empty")
	req.Header.Set("referer", "https://fanyi.caiyunapp.com/")
	req.Header.Set("accept-language", "zh-CN,zh;q=0.9")
	resp, err := client.Do(req)
	if err != nil {
		log.Fatal(err)
	}
	defer resp.Body.Close()
	bodyText, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		log.Fatal(err)
	}
	if resp.StatusCode != 200 {
		log.Fatal("bad StatusCode:", resp.StatusCode, "body", string(bodyText))
	}
	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() {
	if len(os.Args) != 2 {
		fmt.Fprintf(os.Stderr, `usage: simpleDict WORD
example: simpleDict hello
		`)
		os.Exit(1)
	}
	word := os.Args[1]
	query(word)
}