使用Go语言实现一个简单的在线词典 | 青训营笔记

261 阅读4分钟

这是我参与「第五届青训营 -后端场」笔记创作活动的的第1篇笔记

1 介绍

  • 功能:用户可以在命令行输入想要查询的单词,然后程序会通过调用第三方翻译的API查询单词的翻译内容,并将查询结果打印到终端显示出来
  • 技术要点:Go、HTTP请求的发送和响应的处理、解析JSON

2 实现过程

2.1 翻译引擎

采用了视频中所说的火山引擎

2.2 抓包

打开火山翻译引擎的网页,然后按F12或点击鼠标右键“检查”打开开发者工具

在输入完单词进行查询之后,就会出现如图所示的翻译文件

image.png

2.3 代码生成

右键该文件,并复制其cURL到 curlconverter.com/#go然后复制下来写到本地文件main.go

image.png

image.png

运行程序可以得到

image.png 接着对请求结果进行处理

2.4 生成resquest body

image.png 将其复制下来到oktools.net/json2go 可以生成结构体

image.png

接着将

var data = strings.NewReader(`{"source":"youdao","words":["good"],"source_language":"en","target_language":"zh"}`)

修改为

image.png

2.5解析response body

不知道是我电脑的问题还是怎么回事,跟所教学的不太一样,不过,我会出手!

image.png 在响应这里,将其复制到oktools.net/json2go 进行解析,可以得到

image.png

接下来将之前读取的响应内容,使用json.Unmarshal方法反序列化到结构体中,即将主函数最后的fmt.Printf("%s\n", bodyText)这行语句,修改变成:

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

此时响应内容以JSON格式存储在了dictResponse中。

2.6 打印结果

因为要查询任意单词,所以将之前的主函数改为一个参数为单词字符串的查询函数,即将func main()改为func query(word []string),将查询特定good单词的语句 request := DictRequest{Source: "youdao", Words: "["good"]", SourceLanguage: "en", TargetLanguage: "zh"} 改为 request := DictRequest{Source: "youdao", Words: word, SourceLanguage: "en", TargetLanguage: "zh"} ,并添加主函数:

func main() {
    if len(os.Args) != 2 {
        fmt.Fprintf(os.Stderr, `usage: simpleDict WORD example: simpleDict hello`)
        os.Exit(1)
    }
    query(os.Args[1:])
}

此时在命令行下进入文件目录后输入go run main.go word,即可对指定单词进行查询

2.7 继续解析response

如果就按照刚才的进行输出,还是乱序无章,观察 image.png 可以看到结果都在第二层detail里面,于是可以在做完第一次json.Unmarshal方法反序列化到结构体中之后取其detail,Detail := dictResponse.Details[0].Detail然后将其输出

image.png 根据输出结果建立结构体(复制到oktools.net/json2go 进行解析)

image.png

image.png

2.8 完整代码

package main

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

type DictRequest struct {
	Source         string   `json:"source"`
	Words          []string `json:"words"`
	SourceLanguage string   `json:"source_language"`
	TargetLanguage string   `json:"target_language"`
}
type DictResponse struct {
	Details []struct {
		Detail string `json:"detail"`
		Extra  string `json:"extra"`
	} `json:"details"`
	BaseResp struct {
		StatusCode    int    `json:"status_code"`
		StatusMessage string `json:"status_message"`
	} `json:"base_resp"`
}
type DictResponse_Detail struct {
	ErrorCode string `json:"errorCode"`
	RequestID string `json:"requestId"`
	Msg       string `json:"msg"`
	Result    []struct {
		Ec struct {
			ReturnPhrase []string `json:"returnPhrase"`
			Synonyms     []struct {
				Pos   string   `json:"pos"`
				Words []string `json:"words"`
				Trans string   `json:"trans"`
			} `json:"synonyms"`
			Etymology struct {
				ZhCHS []struct {
					Description string `json:"description"`
					Detail      string `json:"detail"`
					Source      string `json:"source"`
				} `json:"zh-CHS"`
			} `json:"etymology"`
			SentenceSample []struct {
				Sentence     string `json:"sentence"`
				SentenceBold string `json:"sentenceBold"`
				Translation  string `json:"translation"`
				Source       string `json:"source"`
			} `json:"sentenceSample"`
			WebDict string `json:"webDict"`
			Web     []struct {
				Phrase   string   `json:"phrase"`
				Meanings []string `json:"meanings"`
			} `json:"web"`
			MTerminalDict string `json:"mTerminalDict"`
			RelWord       struct {
				Word string `json:"word"`
				Stem string `json:"stem"`
				Rels []struct {
					Rel struct {
						Pos   string `json:"pos"`
						Words []struct {
							Word string `json:"word"`
							Tran string `json:"tran"`
						} `json:"words"`
					} `json:"rel"`
				} `json:"rels"`
			} `json:"relWord"`
			Dict  string `json:"dict"`
			Basic struct {
				UsPhonetic string   `json:"usPhonetic"`
				UsSpeech   string   `json:"usSpeech"`
				Phonetic   string   `json:"phonetic"`
				UkSpeech   string   `json:"ukSpeech"`
				ExamType   []string `json:"examType"`
				Explains   []struct {
					Pos   string `json:"pos"`
					Trans string `json:"trans"`
				} `json:"explains"`
				UkPhonetic  string `json:"ukPhonetic"`
				WordFormats []struct {
					Name  string `json:"name"`
					Value string `json:"value"`
				} `json:"wordFormats"`
			} `json:"basic"`
			Phrases []struct {
				Phrase   string   `json:"phrase"`
				Meanings []string `json:"meanings"`
			} `json:"phrases"`
			Lang   string `json:"lang"`
			IsWord bool   `json:"isWord"`
		} `json:"ec"`
	} `json:"result"`
}

func query(w []string) {
	client := &http.Client{}
	// var data = strings.NewReader(`{"source":"youdao","words":["good"],"source_language":"en","target_language":"zh"}`)
	request := DictRequest{Source: "youdao", Words: w, SourceLanguage: "en", TargetLanguage: "zh"}
	buf, err := json.Marshal(request)

	if err != nil {
		log.Fatal(err)
	}
	var data = bytes.NewReader(buf)
	req, err := http.NewRequest("POST", "https://translate.volcengine.com/web/dict/detail/v1/?msToken=&X-Bogus=DFSzswVLQDaZVwrASZWeZ37TlqSX&_signature=_02B4Z6wo00001bQXZJQAAIDCIME.mlnFBXW0F2AAAA7HCjAJYYrhhoQpKtCNBZ4DvM3uCw2HmLtMw9tRYCIsQF1PdGVb8Qco3.OJBjWm74knkFabcutJC8rwMRONm5rvh2WHbxXQlkAGb5aRea", data)
	if err != nil {
		log.Fatal(err)
	}

	req.Header.Set("authority", "translate.volcengine.com")
	req.Header.Set("accept", "application/json, text/plain, */*")
	req.Header.Set("accept-language", "zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7")
	req.Header.Set("content-type", "application/json")
	req.Header.Set("cookie", "x-jupiter-uuid=16737874782996226; i18next=zh-CN; s_v_web_id=verify_lcxduk3g_aatU4Zh1_znbW_4LK1_Bl4d_K3w7RCsU8teA; ttcid=6150c6c309cc40fea7cc6e96f1e2b2a414; tt_scid=7NTge.aVQRRHaMQSMrZLus.Lq8aGpQ10EO9N8QMv9Uu0EpMH-b3YvEDTJqFQmNv90bdc")
	req.Header.Set("origin", "https://translate.volcengine.com")
	req.Header.Set("referer", "https://translate.volcengine.com/mobile?category=&home_language=zh&source_language=detect&target_language=zh&text=good")
	req.Header.Set("sec-ch-ua", `"Not?A_Brand";v="8", "Chromium";v="108", "Google Chrome";v="108"`)
	req.Header.Set("sec-ch-ua-mobile", "?0")
	req.Header.Set("sec-ch-ua-platform", `"macOS"`)
	req.Header.Set("sec-fetch-dest", "empty")
	req.Header.Set("sec-fetch-mode", "cors")
	req.Header.Set("sec-fetch-site", "same-origin")
	req.Header.Set("user-agent", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36")
	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)
	}
	var dictResponse DictResponse
	err = json.Unmarshal(bodyText, &dictResponse)
	if err != nil {
		log.Fatal(err)
	}

	Detail := dictResponse.Details[0].Detail
	var detail DictResponse_Detail
	err = json.Unmarshal([]byte(Detail), &detail)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println("[US: ", detail.Result[0].Ec.Basic.UsPhonetic, "]", "[UK: ", detail.Result[0].Ec.Basic.UkPhonetic, "]")
	for i, item := range detail.Result[0].Ec.Basic.Explains {
		fmt.Println(i+1, item.Pos, item.Trans)
	}
}

func main() {
	if len(os.Args) != 2 {
		fmt.Fprint(os.Stderr, "usage: simpleDict WORD example: simpleDict hello", os.Args[0])
		os.Exit(1)
	}

	query(os.Args[1:])
}

image.png