这是我参与「第五届青训营 」伴学笔记创作活动的第 3 天
前言
本文是介绍用Go实现一个简易版的在线英语单词查询功能,该功能主要是调用第三方在线Api实现英语单词的翻译功能。
在本文中将使用到以下技术点:json解析、http请求、获取命令行参数、浏览器网络抓包。
本次采用翻译软件为彩云小译,找了其他网站发现都需要签名┭┮﹏┭┮。
网页抓包
打开翻译网页,在网页中间右键选择审查或Inspect打开网页控制台。
输入要查询的单词,在控制台中选择web这个请求,如图,可以看到我们需要的信息在图中的标记5中。
代码生成
在请求单词查询接口,可以看到有很多参数以及请求头,要是一个一个的写有点麻烦,好在有网站可以根据请求在线生成代码。
首先在浏览器控制台中,选中接口右键选择Copy -> Copy as cURL如图。
复制出来的内容如下:
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,zh-TW;q=0.7' \
-H 'app-name: xy' \
-H 'cache-control: no-cache' \
-H 'content-type: application/json;charset=UTF-8' \
-H 'device-id: ' \
-H 'origin: https://fanyi.caiyunapp.com' \
-H 'os-type: web' \
-H 'os-version: ' \
-H 'pragma: no-cache' \
-H 'referer: https://fanyi.caiyunapp.com/' \
-H 'sec-ch-ua: "Google Chrome";v="105", "Not)A;Brand";v="8", "Chromium";v="105"' \
-H 'sec-ch-ua-mobile: ?0' \
-H 'sec-ch-ua-platform: "macOS"' \
-H 'sec-fetch-dest: empty' \
-H 'sec-fetch-mode: cors' \
-H 'sec-fetch-site: cross-site' \
-H 'user-agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/105.0.0.0 Safari/537.36' \
-H 'x-authorization: token:qgemv4jr1y38jyq6vhvi' \
--data-raw '{"trans_type":"en2zh","source":"hello"}' \
--compressed
打开代码生成网址,将复制的cURL粘贴进去就能得到请求对应的代码。
生成的代码如下:
&http.Client{}为创建一个httpclient,创建的时候可以指定一些参数,比如超时时间等,不指定就是不限制时间。
http.NewRequest创建一个http请求,参数为请求方式(GET/POST)、请求URL以及请求参数。
req.Header.Set设置请求头参数,有些参数不是必须的话可以删掉。
client.Do发起请求并返回内容以及错误信息。
resp为请求响应流,为了避免资源泄露,需要对流进行关闭。
defer一般用于资源的释放和异常的捕捉, defer语句会将其后面跟随的语句进行延迟处理,将会在程序进行最后的return之后再执行。如果一个函数中有多个defer的话,会从下往上执行,也就是最后被defer的语句,最先被执行。
JSON转化
因为请求得到的内容是个字符串,而且有很多不需要的信息,接下来就是要把得到的字符串转为JSON。
需要定义一个结构体与请求后的response来对应起来用来接收数据,通过JSON反序列化到结构体里即可。
因为response返回的数据非常多而且复杂,自己书写起来很容易出错,所以我们可以通过在线生成代码工具来帮助我们生成代码。
打开这个网站,把浏览器response的内容复制到网站里点击转换-嵌套就能生成对应的结构体。
删除无用的字段,得到结果如下:
type DictResp struct {
Dictionary struct {
Prons struct {
EnUs string `json:"en-us"`
En string `json:"en"`
} `json:"prons"`
Explanations []string `json:"explanations"`
} `json:"dictionary"`
}
接下来是对请求响应体进行JSON反序列化:
var dictResp DictResp
err = json.Unmarshal(bodyText, &dictResp)
if err != nil {
log.Fatal(err)
}
fmt.Println(word, "UK:", dictResp.Dictionary.Prons.En, "US:", dictResp.Dictionary.Prons.EnUs)
for _, item := range dictResp.Dictionary.Explanations {
fmt.Println(item)
}
运行一下看下结果:
读取参数
接下来是从命令行读取参数,命令行参数可以通过os.Args来获取。
下面来看一个简单例子:
func main() {
fmt.Println(os.Args)
}
通过go run main.go hello运行,可以获得两个参数,一个是临时执行路径,另一个是自己输入的参数hello,如下:
[/var/folders/tk/gcvj01wx7m92km/T/go-build446/b001/exe/main hello]
获取参数代码如下:
func main() {
// 判断参数的数量要为2个,否则提示错误
if len(os.Args) != 2 {
fmt.Fprintf(os.Stderr, `usage: simpleDict WORD
example: simpleDict hello`)
os.Exit(1)
}
word := os.Args[1]
query(word)
}
完整代码
好了,到目前为止一个查单词的软件就实现了,完整的代码就不贴出来了,已经放到码上掘金了。