GO语言实战案例-翻译工具 | 青训营笔记

100 阅读3分钟

这篇笔记用来记录我在做实战案例里的翻译工具中遇到的问题。

在课后练习中,我使用有道翻译作为第二个翻译工具

首先先打开有道翻译www.youdao.com/ 打开开发者中心,输入单词,在network中找到我们需要的post请求

image.png

在payload里我们可以找到发送请求需要的参数

image.png 不同于彩云翻译的是,这里是form data格式,因此我们并不需要自己定义发送请求的结构体,直接将string格式的word传进去就好,这里也是使用课程中的网站来直接转换请求的curl,然后修改一下发送过去的data参数。这样我们发送请求阶段就完成了。 总的来说,就是通过api调用,用POST请求发送我们的数据,再由它返回给我们数据,而我们需要对其数据进行处理,找到我们要的那部分就好。

func querybyYoudao(word string) {
	client := &http.Client{}
	var data = strings.NewReader("q=" + word + "&le=en&t=0&client=web&sign=bf6bfdc7703fc2ef45ce74f6b7ff6e40&keyfrom=webdict")
	req, err := http.NewRequest("POST", "https://dict.youdao.com/jsonapi_s?doctype=json&jsonversion=4", data)
	if err != nil {
		log.Fatal(err)
	}
	req.Header.Set("Accept", "application/json, text/plain, */*")
	req.Header.Set("Accept-Language", "zh-CN,zh;q=0.9")
	req.Header.Set("Connection", "keep-alive")
	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
	req.Header.Set("Cookie", "OUTFOX_SEARCH_USER_ID=1474111096@10.112.57.88; OUTFOX_SEARCH_USER_ID_NCOO=1361789659.5254738")
	req.Header.Set("Origin", "https://www.youdao.com")
	req.Header.Set("Referer", "https://www.youdao.com/")
	req.Header.Set("Sec-Fetch-Dest", "empty")
	req.Header.Set("Sec-Fetch-Mode", "cors")
	req.Header.Set("Sec-Fetch-Site", "same-site")
	req.Header.Set("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36")
	req.Header.Set("sec-ch-ua", `"Not_A Brand";v="99", "Google Chrome";v="109", "Chromium";v="109"`)
	req.Header.Set("sec-ch-ua-mobile", "?0")
	req.Header.Set("sec-ch-ua-platform", `"Windows"`)

	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)
	}
	if resp.StatusCode != 200 {
		log.Fatal("bad StatusCode:", resp.StatusCode, "body", string(bodyText))
	}
	var dictResponse2 AutoGenerated
	err = json.Unmarshal(bodyText, &dictResponse2)
	if err != nil {
		log.Fatal(err)
	}

	fmt.Println(word, "UK:", dictResponse2.Ec.Word.Ukphone, "US:", dictResponse2.Ec.Word.Usphone)
	for _, item := range dictResponse2.Ec.Word.Trs {
		fmt.Println(item)
	}

}

由于返回的是JSON格式的字符串,我们需要将其反序列化,并找到我们的翻译结果进行输出。 通过 JSON转Golang Struct - 在线工具 - OKTools 来将返回的 JSON 字符串转换为对应的 struct,并通过 json.Unmarshal 方法来对返回的结果进行处理,并保存到结构体变量中:

有道词典里preview里的JSON内容非常多,而且我在转过去之后发现有许多定义不明确的内容,我们只需要找到翻译结果的那部分JSON并将他转换成结构体就好。

image.png 也就是上面的EC这部分

type AutoGenerated struct {
	Ec struct {
		WebTrans []string `json:"web_trans"`
		Special  []struct {
			Nat   string `json:"nat"`
			Major string `json:"major"`
		} `json:"special"`
		ExamType []string `json:"exam_type"`
		Source   struct {
			Name string `json:"name"`
			URL  string `json:"url"`
		} `json:"source"`
		Word struct {
			Usphone  string `json:"usphone"`
			Ukphone  string `json:"ukphone"`
			Ukspeech string `json:"ukspeech"`
			Trs      []struct {
				Pos  string `json:"pos,omitempty"`
				Tran string `json:"tran"`
			} `json:"trs"`
			Wfs []struct {
				Wf struct {
					Name  string `json:"name"`
					Value string `json:"value"`
				} `json:"wf"`
			} `json:"wfs"`
			ReturnPhrase string `json:"return-phrase"`
			Usspeech     string `json:"usspeech"`
		} `json:"word"`
	} `json:"ec"`
}

最后将请求返回的结果通过反序列化转换到结构体,然后输出就好了

var dictResponse2 AutoGenerated
	err = json.Unmarshal(bodyText, &dictResponse2)
	if err != nil {
		log.Fatal(err)
	}

	fmt.Println(word, "UK:", dictResponse2.Ec.Word.Ukphone, "US:", dictResponse2.Ec.Word.Usphone)
	for _, item := range dictResponse2.Ec.Word.Trs {
		fmt.Println(item)
	}

运行代码,可以成功运行

image.png

事实上,我在用有道翻译之前也尝试过用百度翻译,百度翻译也是FORM DATA格式,但是我并不能成功使用。在检查过程中,我发现使用百度的请求无法返回正确的JSON,导致在转换结构体这阶段找不到我要的内容。我并没有成功解决这个问题。只能说我自己的水平确实有限。还需多多学习。