这次的难度比上一个猜数游戏的难度要高一些,原因在于我们需要和外部网络进行连接。和外部网络连接的方式在于接口(API),我们要调用一个接口,获取JSON字符串,实现简易版本的词典。 注:最好有一定项目基础,至少知道前后端再来阅读本文。
项目需求
- 调用接口,为翻译提供支持
- 使用go的http协议相关内容
- 新增额外的词典,更改代码,支持查询
实现思路
- 巧妙地使用编程网站,用windows的审查元素得到所需JSON格式。
- 用vscode实现整体统合
步骤、代码及路径
获取JSON字符串
寻找网站
本次实验网站:
网络元素审查
在网页上点击鼠标右键,如图操作,进行审查元素。
之后界面如图所示:
寻找POST格式的JSON
不了解JSON的同学可以看看这个链接:
[JSON的三种格式_json格式_daxiong0816的博客-CSDN博客] (blog.csdn.net/daxiong0816…)
首先,我们要随便输入一个英文单词,让它进行翻译,观察审查元素中“网络”这一栏的变化,然后找到“dict”或者其它相关文件夹。
点击dict文件夹,我们要找到“标头”的method是POST形式的请求,这和前端ajax相关,感兴趣的同学们可以去搜一搜ajax。
在这种情况下,它的载荷是:
它的预览是:
如果与上述两张图片相同,那么说明位置正确,其中载荷是发送过去的请求,预览是后端传回来的请求。
JSON代码部分
如果要让我们自己来完整这段的写法,那会相当复杂,因此我们可以用另一种方式,即提交给网站,让它来帮忙写。 在提交之前,我们需要先得到网站需要的格式:
接着,打开代码生成的网址:代码生成,将刚刚复制得到的内容粘贴到上面。 注意,语言选择GO,右上角选择POST才可生成,如下图所示:
代码如下:
package main
import (
"fmt"
"io"
"log"
"net/http"
"strings"
)
func main() {
client := &http.Client{}
var data = strings.NewReader(`msg1=wow&msg2=such&msg3=data`)//是个流
//req是创建的请求,可以参考ajax相关内容
req, err := http.NewRequest("POST", "http://fiddle.jshell.net/echo/html/", data)
if err != nil {
log.Fatal(err)
}
req.Header.Set("Origin", "http://fiddle.jshell.net")
// req.Header.Set("Accept-Encoding", "gzip, deflate")
req.Header.Set("Accept-Language", "en-US,en;q=0.8")
req.Header.Set("User-Agent", "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.5359.125 Safari/537.36")
req.Header.Set("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8")
req.Header.Set("Accept", "*/*")
req.Header.Set("Referer", "http://fiddle.jshell.net/_display/")
req.Header.Set("X-Requested-With", "XMLHttpRequest")
req.Header.Set("Connection", "keep-alive")
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字符串
}
但是可能会出现一些由于代码复杂而产生的编译错误,直接删除即可,如果没有错误那就更好了,可以运行,将字符串打印出来。
生成requestBody
需要注意的是,需要什么类型的data就出现什么类型的对象:
解析requestBody
我们可以发现,前面出现的结构体非常复杂,如果选择自己来写的话难免会出错,因此,我们同样调用代码生成网站,注意选择转化嵌套,如图所示:
将整个JSON字符串复制下来:
粘贴并选择嵌套模式
单击之后右侧改变
解析整个结构体
在前文,我们打印了整个JSON字符串,现在要对代码进行修改,JSON字符串BodyTest以结构体中的一个属性值存在,代码如下:
var dictResponse DictResponse
err = json.Unmarshal(bodyText, &dictResponse)
if err != nil {
log.Fatal(err)
}
fmt.Printf("%#v\n", dictResponse)
打印结果
在打印结果之前,我们可以了解一些关于状态码的知识,如果后端返回的状态码错误,我们一样得不到正确的结果,所以我们应该加上这段代码来判断状态的正确性:
if resp.StatusCode != 200 {
log.Fatal("bad StatusCode:", resp.StatusCode, "body", string(bodyText))
}
此外,我们不能忘记整个结构主体:
fmt.Println(word, "UK:", dictResponse.Dictionary.Prons.En, "US:", dictResponse.Dictionary.Prons.EnUs)
for _, item := range dictResponse.Dictionary.Explanations {
fmt.Println(item)
}
新增其它词典支持
本次选择的第二个词典为百度翻译。
新增的思路
两个词典可能有所不同:
- JSON格式不同
- 返回值的BodyRequest不同
因此,我们需要对其进行一定的改动。 老规矩,同样根据生成代码的网站来生成上述的两个代码:
package main
import (
"fmt"
"io"
"log"
"net/http"
"strings"
)
func main() {
client := &http.Client{}
var data = strings.NewReader(`msg1=wow&msg2=such&msg3=data`)
req, err := http.NewRequest("POST", "http://fiddle.jshell.net/echo/html/", data)
if err != nil {
log.Fatal(err)
}
req.Header.Set("Origin", "http://fiddle.jshell.net")
// req.Header.Set("Accept-Encoding", "gzip, deflate")
req.Header.Set("Accept-Language", "en-US,en;q=0.8")
req.Header.Set("User-Agent", "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.5359.125 Safari/537.36")
req.Header.Set("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8")
req.Header.Set("Accept", "*/*")
req.Header.Set("Referer", "http://fiddle.jshell.net/_display/")
req.Header.Set("X-Requested-With", "XMLHttpRequest")
req.Header.Set("Connection", "keep-alive")
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)
}
以上是第一个生成代码。
type AutoGenerated struct {
TransResult struct {
Data []struct {
Dst string `json:"dst"`
Src string `json:"src"`
} `json:"data"`
From string `json:"from"`
To string `json:"to"`
Status int `json:"status"`
Type int `json:"type"`
Phonetic []struct {
SrcStr string `json:"src_str"`
TrgStr string `json:"trg_str"`
} `json:"phonetic"`
} `json:"trans_result"`
DictResult struct {
Edict struct {
Item []struct {
TrGroup []struct {
Tr []string `json:"tr"`
Example []string `json:"example"`
SimilarWord []string `json:"similar_word"`
} `json:"tr_group"`
Pos string `json:"pos"`
} `json:"item"`
Word string `json:"word"`
} `json:"edict"`
From string `json:"from"`
SimpleMeans struct {
WordName string `json:"word_name"`
From string `json:"from"`
WordMeans []string `json:"word_means"`
Tags struct {
Core []string `json:"core"`
Other []string `json:"other"`
} `json:"tags"`
Exchange struct {
WordPl []string `json:"word_pl"`
} `json:"exchange"`
Symbols []struct {
PhEn string `json:"ph_en"`
PhAm string `json:"ph_am"`
Parts []struct {
Part string `json:"part"`
Means []string `json:"means"`
} `json:"parts"`
PhOther string `json:"ph_other"`
} `json:"symbols"`
} `json:"simple_means"`
Common struct {
Text string `json:"text"`
From string `json:"from"`
} `json:"common"`
GeneralKnowledge struct {
SimilarWords []struct {
En string `json:"en"`
Zh string `json:"zh"`
} `json:"similar_words"`
WordName string `json:"word_name"`
WordLang string `json:"word_lang"`
WordType string `json:"word_type"`
} `json:"general_knowledge"`
Collins struct {
Entry []struct {
EntryID string `json:"entry_id"`
Type string `json:"type"`
Value []struct {
MeanType []struct {
InfoType string `json:"info_type"`
InfoID string `json:"info_id"`
Example []struct {
ExampleID string `json:"example_id"`
TtsSize string `json:"tts_size"`
Tran string `json:"tran"`
Ex string `json:"ex"`
TtsMp3 string `json:"tts_mp3"`
} `json:"example"`
} `json:"mean_type"`
Gramarinfo []interface{} `json:"gramarinfo"`
Tran string `json:"tran"`
Def string `json:"def"`
MeanID string `json:"mean_id"`
Posp []struct {
Label string `json:"label"`
} `json:"posp"`
} `json:"value"`
} `json:"entry"`
WordName string `json:"word_name"`
Frequence string `json:"frequence"`
WordEmphasize string `json:"word_emphasize"`
WordID string `json:"word_id"`
} `json:"collins"`
Lang string `json:"lang"`
Oxford struct {
Entry []struct {
Tag string `json:"tag"`
Name string `json:"name"`
Data []struct {
Tag string `json:"tag"`
Data []struct {
Tag string `json:"tag"`
P string `json:"p"`
PText string `json:"p_text"`
} `json:"data"`
} `json:"data"`
} `json:"entry"`
Unbox string `json:"unbox"`
} `json:"oxford"`
Sanyms []struct {
Tit string `json:"tit"`
Data []struct {
P string `json:"p"`
D []string `json:"d"`
} `json:"data"`
Type string `json:"type"`
} `json:"sanyms"`
Usecase struct {
Idiom []struct {
P string `json:"p"`
Tag string `json:"tag"`
Data []struct {
Tag string `json:"tag"`
Data []struct {
EnText string `json:"enText"`
Tag string `json:"tag"`
ChText string `json:"chText"`
Before []struct {
Tag string `json:"tag"`
Data []struct {
RText string `json:"r_text"`
R string `json:"r"`
Tag string `json:"tag"`
} `json:"data"`
} `json:"before,omitempty"`
} `json:"data"`
} `json:"data"`
} `json:"idiom"`
} `json:"usecase"`
BaiduPhrase []struct {
Tit []string `json:"tit"`
Trans []string `json:"trans"`
} `json:"baidu_phrase"`
Synonym []struct {
Synonyms []struct {
Tips string `json:"tips"`
Bx string `json:"bx"`
Syn struct {
P string `json:"p"`
Word string `json:"word"`
D []string `json:"d"`
} `json:"syn"`
Ex []struct {
EnText string `json:"enText"`
ChText string `json:"chText"`
} `json:"ex"`
} `json:"synonyms"`
Guide string `json:"guide"`
Words []string `json:"words"`
} `json:"synonym"`
QueryExplainVideo struct {
ID int `json:"id"`
UserID string `json:"user_id"`
UserName string `json:"user_name"`
UserPic string `json:"user_pic"`
Query string `json:"query"`
Direction string `json:"direction"`
Type string `json:"type"`
Tag string `json:"tag"`
Detail string `json:"detail"`
Status string `json:"status"`
SearchType string `json:"search_type"`
FeedURL string `json:"feed_url"`
Likes string `json:"likes"`
Plays string `json:"plays"`
CreatedAt string `json:"created_at"`
UpdatedAt string `json:"updated_at"`
DuplicateID string `json:"duplicate_id"`
RejectReason string `json:"reject_reason"`
CoverURL string `json:"coverUrl"`
VideoURL string `json:"videoUrl"`
ThumbURL string `json:"thumbUrl"`
VideoTime string `json:"videoTime"`
VideoType string `json:"videoType"`
} `json:"queryExplainVideo"`
} `json:"dict_result"`
LijuResult struct {
Double string `json:"double"`
Tag []string `json:"tag"`
Single string `json:"single"`
} `json:"liju_result"`
Logid int `json:"logid"`
}
以上是第二段结构体的生成代码。
我们发现,这两个代码与之前的彩云翻译有所区别,甚至区别不小。因此,不能让一个请求搞定两个翻译的格式。 由此,我提出了另一个想法,那就是准备两个请求,一个命名为req1,另一个为req2,同时按照各自的格式进行请求。 这个“同时”的代码需要用到go语言的并行设置,见之后的笔记。