Go语言实践 在线词典 | 青训营

2023年 8月 26日 30.5k 0

开头

本文简单的完成了在线词典课后作业的两个要求:

  • 增加了另一种翻译引擎的支持
  • 在上一步的基础上实现并行请求两个翻译引擎来提高响应速度。

步骤

选择翻译引擎

这里我选择的是360翻译引擎。其他的翻译引擎我都没有做出很好的解析效果,要么就是有奇奇怪怪的限制。鉴于自身实力问题,就选择了360翻译引擎。

抓包

image.png
通过翻译一个hello,找到了对应的翻译请求。

生成代码

image.png
右键->复制->复制为cURL(bash)
打开Convert curl to Go (curlconverter.com)Convert curl to Go (curlconverter.com)进行代码生成

package main

import (
	"fmt"
	"io"
	"log"
	"net/http"
)

func main() {
	client := &http.Client{}
	req, err := http.NewRequest("POST", "https://fanyi.so.com/index/search?eng=1&validate=&ignore_trans=0&query=hello", nil)
	if err != nil {
		log.Fatal(err)
	}
	req.Header.Set("authority", "fanyi.so.com")
	req.Header.Set("accept", "application/json, text/plain, */*")
	req.Header.Set("accept-language", "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6")
	req.Header.Set("content-length", "0")
	req.Header.Set("cookie", "__huid=11wNJd%2BocFVfC2mya6DFn8FR9YfXKFnBmnHDhVe65YE1s%3D; so_huid=11wNJd%2BocFVfC2mya6DFn8FR9YfXKFnBmnHDhVe65YE1s%3D; __gid=9114931.775463156.1631263986380.1640166943863.150; QiHooGUID=97C410ED2C00E0D3A4F6B11516982081.1690537261562; Q_UDID=bb97a741-52ee-a963-d0ca-ce922256998c; __guid=144965027.578392690600855000.1692957328745.652; count=1")
	req.Header.Set("dnt", "1")
	req.Header.Set("origin", "https://fanyi.so.com")
	req.Header.Set("pro", "fanyi")
	req.Header.Set("referer", "https://fanyi.so.com/")
	req.Header.Set("sec-ch-ua", `"Chromium";v="116", "Not)A;Brand";v="24", "Microsoft Edge";v="116"`)
	req.Header.Set("sec-ch-ua-mobile", "?1")
	req.Header.Set("sec-ch-ua-platform", `"Android"`)
	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("sec-gpc", "1")
	req.Header.Set("user-agent", "Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Mobile Safari/537.36 Edg/116.0.1938.54")
	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("%sn", bodyText)
}

生成请求

http.NewRequest("POST", "https://fanyi.so.com/index/search?eng=1&validate=&ignore_trans=0&query=hello", nil)

分析这段代码可以知道,翻译的单词是直接拼接在query后面的,所以可以采用拼接的方式把要翻译的单词拼接上去即可。

http.NewRequest("POST", fmt.Sprintf("https://fanyi.so.com/index/search?eng=1&validate=&ignore_trans=0&query=%s", word), nil)

这样请求就构造好了。

生成响应体response body

image.png
右键->复制值
打开工具网站
JSON转Golang Struct - 在线工具 - OKTools

image.png
转换为嵌套结构体:

type AutoGenerated struct {
	Data struct {
		Explain struct {
			EnglishExplain []interface{} `json:"english_explain"`
			Word           string        `json:"word"`
			Caiyun         struct {
				Info struct {
					Lbsynonym    []interface{} `json:"lbsynonym"`
					Antonym      []interface{} `json:"antonym"`
					WordExchange []interface{} `json:"word_exchange"`
				} `json:"info"`
			} `json:"caiyun"`
			RelatedWords []interface{} `json:"related_words"`
			WordLevel    []string      `json:"word_level"`
			Exsentence   []struct {
				Title string `json:"Title"`
				Body  string `json:"Body"`
				URL   string `json:"Url"`
			} `json:"exsentence"`
			Phonetic struct {
				NAMING_FAILED string `json:"英"`
			} `json:"phonetic"`
			WebTranslations []struct {
				Translation string `json:"translation"`
				Example     string `json:"example"`
			} `json:"web_translations"`
			Translation []string `json:"translation"`
		} `json:"explain"`
		Fanyi    string `json:"fanyi"`
		SpeakURL struct {
			SpeakURL     string `json:"speak_url"`
			TSpeakURL    string `json:"tSpeak_url"`
			WordSpeakURL string `json:"word_speak_url"`
			WordType     string `json:"word_type"`
		} `json:"speak_url"`
		Vendor string `json:"vendor"`
	} `json:"data"`
	Error int    `json:"error"`
	Msg   string `json:"msg"`
}

我们需要请求的数据就在result.Data.Explain.Phonetic.NAMING_FAILEDresult.Data.Explain.Translation里面。

完善代码

func queryBy360(word string) {
	client := &http.Client{}
	req, err := http.NewRequest("POST", fmt.Sprintf("https://fanyi.so.com/index/search?eng=1&validate=&ignore_trans=0&query=%s", word), nil)
	if err != nil {
		log.Fatal(err)
	}
	req.Header.Set("authority", "fanyi.so.com")
	req.Header.Set("accept", "application/json, text/plain, */*")
	req.Header.Set("accept-language", "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6")
	req.Header.Set("content-length", "0")
	req.Header.Set("cookie", "__huid=11wNJd%2BocFVfC2mya6DFn8FR9YfXKFnBmnHDhVe65YE1s%3D; so_huid=11wNJd%2BocFVfC2mya6DFn8FR9YfXKFnBmnHDhVe65YE1s%3D; __gid=9114931.775463156.1631263986380.1640166943863.150; __guid=65846823.4096180342024496000.1666005986099.6982; QiHooGUID=97C410ED2C00E0D3A4F6B11516982081.1690537261562; Q_UDID=bb97a741-52ee-a963-d0ca-ce922256998c; count=1")
	req.Header.Set("dnt", "1")
	req.Header.Set("origin", "https://fanyi.so.com")
	req.Header.Set("pro", "fanyi")
	req.Header.Set("referer", "https://fanyi.so.com/")
	req.Header.Set("sec-ch-ua", `"Not/A)Brand";v="99", "Microsoft Edge";v="115", "Chromium";v="115"`)
	req.Header.Set("sec-ch-ua-mobile", "?1")
	req.Header.Set("sec-ch-ua-platform", `"Android"`)
	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("sec-gpc", "1")
	req.Header.Set("user-agent", "Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/115.0.0.0 Mobile Safari/537.36 Edg/115.0.1901.183")
	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)
	}
	var result AutoGenerated

	err = json.Unmarshal(bodyText, &result)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println("---360翻译---")
	fmt.Println(word, "读音:", result.Data.Explain.Phonetic.NAMING_FAILED)
	for _, item := range result.Data.Explain.Translation {
		fmt.Println(item)
	}
}

这里把360翻译引擎的请求封装成了一个函数。
这样就可以和原有的彩云翻译分开来,提高代码可读性。
然后在main函数里分别调用彩云翻译和360翻译就可以实现串行请求翻译单词了。

改造为并行请求的方式

其实改造为并行请求的方式也很容易,就是开启协程来分别执行这两个函数。同步方式采用sync.WaitGroup来同步两个函数的调用过程,这样就可以做到两个函数并行请求翻译了。

具体代码框架就是:

func main() {
	if len(os.Args) != 2 {
		fmt.Fprintf(os.Stderr, `usage: simpleDict WORD
example: simpleDict hello
		`)
		os.Exit(1)
	}
	word := os.Args[1]
	var wg sync.WaitGroup
	wg.Add(2)
	go queryByCaiYun(word, &wg)
	go queryBy360(word, &wg)
	wg.Wait()
}

小结

其实这个课后作业本身就是比较容易的,按照课件的步骤也能逐步完成。难点就是并行请求的方式,这里我用的是sync.WaitGroup,当然还有其他的同步方式,这里就不介绍了。

相关文章

服务器端口转发,带你了解服务器端口转发
服务器开放端口,服务器开放端口的步骤
产品推荐:7月受欢迎AI容器镜像来了,有Qwen系列大模型镜像
如何使用 WinGet 下载 Microsoft Store 应用
百度搜索:蓝易云 – 熟悉ubuntu apt-get命令详解
百度搜索:蓝易云 – 域名解析成功但ping不通解决方案

发布评论