这是青训营笔记的第七篇文章。
在线词典
首先,我们跟随老师上课讲的,先来看—下我们要用到的API,以彩云科技提供的在线翻译为例。先请打开彩云翻译的网页彩云小译 - 在线翻译 (caiyunapp.com),然后右键检查打开浏览器的开发者工具。
1.抓包
首先点击F12进入开发者工具,在左侧文本框输入一个简单单词,我们点一下翻译按钮,浏览器会发送一系列请求,我们能很轻松地找到那个用来查询单词的请求。
找到这个 post的请求。
我们通过预览,查看该请求返回信息是否使我们想要的单词对应词条信息。
然后我们找到这个请求后,右键这个请求,选择复制为cURL(bash)
2.生成代码
需要在 Golang 里面去发送这个请求。但是这个请求比较复杂,用代码构造很麻烦。可以用一种简单的方式来生成代码,如下
然后打开一个网址,Convert curl commands to Go (curlconverter.com)把刚才复制的代码粘贴到文本框内
获得以下代码,将这个代码粘贴到编辑器中
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)
}
将上述代码运行之后,我们可以得到
但是之前输入是固定的,我们是要从一个变量来输入,我们需要用到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)
}