GO 语言的实战案例及作业

110 阅读18分钟

随机猜数字游戏

使用go语言实现一个简单的猜数字游戏

实现原理

通过 for 和 随机数生成函数 rand.Intn(maxNum)

随机数生成

package main
​
import (
    "fmt"
    "math/rand"
)
​
func main() {
    maxNum := 100
    // GO最新标准已经弃用
    //rand.Seed(time.Now().UnixNano())
    
    // 不需要设定种子即可生成随机数
    // 生成的是 在 [0,maxNum-1] 之间的随机数
    secretNum := rand.Intn(maxNum)
    fmt.Println(secretNum)
}
​
/*
* 27
*/

相关官方文档

func Seed(seed int64)

函数 Seed 已弃用rand package - math/rand - Go Packages

func Seed(seed int64) Seed 使用提供的种子值将默认源初始化为确定性状态。当除以 2³¹-1 时具有相同余数的种子值将生成相同的伪随机序列。与 Rand.Seed 方法不同,Seed 可以安全地用于并发使用。

如果未调用 Seed,则生成器将在程序启动时随机设置种子

在 Go 1.20 之前,生成器在程序启动时类似于 Seed(1) 的方式被设置种子。要强制使用旧的行为,请在程序启动时调用 Seed(1)。或者,在调用此包中的任何函数之前,在环境中设置 GODEBUG=randautoseed=0。

已弃用:从 Go 1.20 开始,没有理由用随机值调用 Seed。调用 Seed 并传入已知值以获取特定结果序列的程序应使用 New(NewSource(seed)) 来获取局部随机生成器。

添加输入

bufio 包

bufio 是一个包,它为 I/O 提供缓冲。

bufio 包提供了一些读取器(Reader)和写入器(Writer)类型,它们在内存中维护一个缓冲区,从而减少对底层 I/O 调用的次数。

常用的类型和函数

类型
  • Reader: 从一个 io.Reader 对象读取数据,并提供缓冲。
  • Writer: 向一个 io.Writer 对象写入数据,并提供缓冲。
  • ReadWriter: 结合了 ReaderWriter,可以同时用于读写。
函数
  • NewReader(rd io.Reader) *Reader: 创建一个新的 Reader,它将从提供的 io.Reader 读取数据。
  • NewWriter(w io.Writer) *Writer: 创建一个新的 Writer,它将向提供的 io.Writer 写入数据。
  • NewReadWriter(r *Reader, w *Writer) *ReadWriter: 创建一个新的 ReadWriter,它将使用提供的 ReaderWriter 进行读写操作。
读取器(Reader)
  • Read(p []byte) (n int, err error): 从缓冲区读取数据到 p 中。
  • ReadByte() (byte, error): 读取并返回一个字节。
  • ReadBytes(delim byte) ([]byte, error): 读取直到遇到分隔符 delim,返回读取的数据(包括分隔符)。
  • ReadString(delim byte) (string, error): 类似于 ReadBytes,但返回的是字符串,包括分隔符
  • Peek(n int) ([]byte, error): 返回缓冲区中下一个 n 个字节,而不进行读取。
写入器(Writer)
  • Write(p []byte) (n int, err error): 将 p 中的数据写入缓冲区。
  • WriteString(s string) (int, error): 将字符串 s 写入缓冲区。
  • WriteByte(c byte) error: 写入一个字节。
  • Flush() error: 将缓冲区中的数据写入底层的 io.Writer。
基本用法
package main
​
import (
    "bufio"
    "bytes"
    "fmt"
    "os"
)
​
func main() {
    // 创建一个新的 bytes.Buffer
    var buffer bytes.Buffer
​
    // 创建一个新的 Writer 和 Reader
    writer := bufio.NewWriter(&buffer)
    reader := bufio.NewReader(&buffer)
​
    // 创建一个 ReadWriter
    readWriter := bufio.NewReadWriter(reader, writer)
​
    // 写入数据
    message := "Hello, B3Q!\n"
    n, err := readWriter.WriteString(message)
    if err != nil {
        fmt.Println("Error writing to buffer:", err)
        return
    }
    fmt.Printf("Wrote %d bytes to buffer by ReadWriter\n", n)
​
    // 刷新缓冲区,确保所有数据都被写入到底层的 io.Writer
    if err := readWriter.Flush(); err != nil {
        fmt.Println("Error flushing buffer:", err)
        return
    }
​
    // 使用 ReadWriter 读取之前写入的数据
    line, err := readWriter.ReadString('\n')
    if err != nil {
        fmt.Println("Error reading from ReadWriter:", err)
        return
    }
    fmt.Printf("Read from ReadWriter: %s", line)
​
}
​

添加输入的随机数生成

package main
​
import (
    "bufio"     
    "fmt"       
    "math/rand" 
    "os"        
    "strconv"   
    "strings"   
)
​
func main() {
    maxNum := 114514                                      // 设置猜测数字的最大范围
    secretNumber := rand.Intn(maxNum)                  // 生成一个0到maxNum-1之间的随机数作为秘密数字
    fmt.Println("The secret number is ", secretNumber) 
​
    fmt.Println("Please input your guess") // 提示用户输入猜测的数字
    reader := bufio.NewReader(os.Stdin)    // 创建一个读取器,从标准输入读取数据
    input, err := reader.ReadString('\n')  // 读取一行输入,直到遇到换行符
    if err != nil {                        // 检查读取过程中是否有错误发生
        fmt.Println("An error occured while reading input. Please try again", err)
        return 
    }
    input = strings.Trim(input, "\r\n") // 去除输入字符串末尾的回车和换行符
​
    guess, err := strconv.Atoi(input) // 将输入的字符串转换为整数
    if err != nil {                   // 检查转换过程中是否有错误发生
        fmt.Println("Invalid input. Please enter an integer value") 
        return
    }
    fmt.Println("You guess is", guess) // 打印用户猜测的数字
}
​

添加for循环和提示

package main
​
import (
    "bufio"      
    "fmt"        
    "math/rand"  
    "os"         
    "strconv"    
    "strings"    
)
​
func main() {
    maxNum := 114514 // 设置猜测数字的最大范围
    secretNumber := rand.Intn(maxNum) // 生成一个0到maxNum-1之间的随机数作为秘密数字
​
    fmt.Println("Please input your guess") // 提示用户输入猜测的数字
​
    reader := bufio.NewReader(os.Stdin) // 创建一个读取器,从标准输入读取数据// 无限循环,直到用户猜对数字
    for {
        input, err := reader.ReadString('\n') // 读取一行输入,直到遇到换行符
        if err != nil { 
            fmt.Println("An error occured while reading input. Please try again", err)
            continue 
        }
        input = strings.Trim(input, "\r\n") // 去除输入字符串末尾的回车和换行符
​
        guess, err := strconv.Atoi(input) // 将输入的字符串转换为整数
        if err != nil { 
            fmt.Println("Invalid input. Please enter an integer value") 
            continue
        }
        fmt.Println("You guess is", guess) // 打印用户猜测的数字// 根据用户猜测的数字与秘密数字的比较,给出相应的提示
        if guess > secretNumber {
            fmt.Println("Your guess is bigger than the secret number. Please try again")
        } else if guess < secretNumber {
            fmt.Println("Your guess is smaller than the secret number. Please try again")
        } else {
            fmt.Println("Correct, you Legend!") // 用户猜对了数字,打印恭喜信息并退出循环
            break // 退出循环
        }
    }
}
​

使用 fmt.Scanf 优化输入

fmt.Scanf

fmt 包提供了一个函数 Scanf,它是用于根据格式字符串从标准输入(通常是键盘输入)读取数据到指定的变量中

func Scanf(format string, a ...interface{}) (n int, err error)
  • format: 一个格式字符串,它指定如何解释输入。格式字符串中的每个格式化动词都会对应一个参数,用于存储读取的值。例如,%d 表示读取一个整数,%s 表示读取一个字符串等。
  • a ...interface{}: 这是一个可变数量的参数,每个参数都必须是一个指向变量的指针。这些变量用于存储 Scanf 读取的值。
  • n: 返回成功读取并赋值的输入项数。
  • err: 返回在读取过程中遇到的任何错误。

示例

package main
​
import "fmt"func main() {
    var name string
    var age int// 提示用户输入姓名和年龄
    fmt.Print("Enter your name and age: ")
​
    // 使用Scanf读取用户输入的姓名和年龄
    // 类似于c语言输入 
    // 其中 %s 输入一个字符串  %d 输入一个数字 它们是格式化动词
    _, err := fmt.Scanf("%s %d", &name, &age)
    if err != nil {
        fmt.Println("Error reading input:", err)
        return
    }
​
    // 打印读取到的值
    fmt.Printf("Hello, %s. You are %d years old.\n", name, age)
}
​
/*
* Enter your name and age: b3q 114514
* Hello, b3q. You are 114514 years old.
*/

其它格式化动词

布尔值

  • %t: 输出布尔值(true 或 false)

整数

  • %d: 输出十进制整数。
  • %b: 输出二进制整数。
  • %c: 输出对应的 Unicode 码点字符。
  • %o: 输出八进制整数。
  • %x: 输出十六进制整数,使用小写字母。
  • %X: 输出十六进制整数,使用大写字母。
  • %U: 输出 Unicode 格式字符(例如 “U+1234”)

浮点数和复数

  • %f: 输出十进制形式的小数或浮点数。
  • %e 或 %E: 输出科学记数法形式(例如 1.234e+02)
  • %g 或 %G: 根据情况选择 %e、%E 或 %f,以更紧凑的方式输出

字符串和字节切片

  • %s: 输出字符串或切片的字符串表示形式。
  • %q: 输出带双引号的字符串或切片的字符串表示形式。
  • %x: 输出十六进制编码的字符串,每个字节用两个十六进制数字表示。
  • %X: 类似 %x,但使用大写字母

指针

  • %p: 输出十六进制表示的指针地址

使用 fmt.Scanf 优化的程序

package main
​
import (
    "fmt"      
    "math/rand" 
)
​
func main() {
    maxNum := 10
    secretNumber := rand.Intn(maxNum)
​
    var guess int
​
    fmt.Println("Please input your guess")
​
    // 无限循环,直到用户猜对数字
    for {
        _, err := fmt.Scanf("%d", &guess) // 使用Scanf读取用户输入的整数
        if err != nil {                   // 检查读取过程中是否有错误发生
            fmt.Println("Invalid input. Please enter an integer value")
            continue
        }
​
        fmt.Println("You guess is", guess) // 打印用户猜测的数字// 根据用户猜测的数字与秘密数字的比较,给出相应的提示
        if guess > secretNumber {
            fmt.Println("Your guess is bigger than the secret number. Please try again")
        } else if guess < secretNumber {
            fmt.Println("Your guess is smaller than the secret number. Please try again")
        } else {
            fmt.Println("Correct, you Legend!") // 用户猜对了数字,打印恭喜信息并退出循环
            break                               // 退出循环
        }
    }
}

简单字典(查单词)

使用go语言通过发送请求实现一个简单查单词功能(简单爬虫)

PS:需要了解HTTP 协议基础内容:请求与响应

实现原理

通过go语言爬取 ajax 请求

爬取网站:彩云翻译

寻找 ajax

首先按 f12 打开控制台,选择网络,点击 XHR

这里使用的是 edge 浏览器

image.png

输入待查询的单词,这里输入的是 tom

image.png

可以发现右边控制台出现了名为dict的ajax请求

image.png

点击 dict,选择预览

image.png

出现了输入单词的中文译文 explanation (Unicode编码格式,因为译文是中文) ,音标 prons。表明这个ajax是要爬取的

点击响应

image.png

可以发现是一个json格式的字符串,接下来就是进行构造请求,获取响应

构造请求

点击标头,可以发现请求的url(链接)是 api.interpreter.caiyunai.com/v1/dict,请求方式是 post,说明客户端(通常是用户的网页浏览器或者是一个应用程序,这里是网页浏览器)需要向服务器发送数据,以获取资源,而get请求则不需要。

image.png

点击负载,查看负载的数据

image.png

可以发现是一个json格式的字符串,说明当向这个url发送post请求时,需要带上上图格式的json格式的字符串,其中

source 表示翻译的文字内容,这是要翻译的是 tom 这个单词

tans_type 表示 从什么语言翻译成另一种语言,这里 en2zh 说明从英文(en)翻译成中文(zh) ,其中的 2 表示 '到' 的意思

接下来进行构造请求

首先点击标头,点击展开 请求标头

image.png

这是要构造的请求的请求头,可以发现请求的方法,请求的协议,请求需要token等内容

需要根据这个请求头进行构造,右键 dict,选择复制为url(bash)

image.png

然后将复制的内容复制到 Convert curl commands to Go (curlconverter.com) ,选择 go

image.png

可以快速生成 go语言类型的请求,这里添加了注释

package main
​
import (
    "fmt"
    "io"
    "log"
    "net/http"
    "strings"
)
​
func main() {
    // 创建一个 HTTP 客户端
    client := &http.Client{}
​
    // 准备请求数据,以 JSON 格式字符串的形式
    var data = strings.NewReader(`{"trans_type":"en2zh","source":"tom"}`)
​
    // 创建一个新的 HTTP POST 请求
    req, err := http.NewRequest("POST", "https://api.interpreter.caiyunai.com/v1/dict", data)
    if err != nil {
        // 如果创建请求时发生错误,记录错误并退出程序
        log.Fatal(err)
    }
​
    // 设置请求头
    req.Header.Set("accept", "application/json, text/plain, */*")             // 设置接受的内容类型
    req.Header.Set("accept-language", "zh")                                    // 设置接受的语言
    req.Header.Set("app-name", "xiaoyi")                                       // 设置应用名称
    req.Header.Set("authorization", "Bearer")                                  // 设置授权类型
    req.Header.Set("content-type", "application/json;charset=UTF-8")          // 设置内容类型为 JSON
    req.Header.Set("device-id", "b7feaa2827a466315abeb73e554ba173")           // 设置设备 ID
    req.Header.Set("origin", "https://fanyi.caiyunapp.com")                   // 设置请求来源
    req.Header.Set("os-type", "web")                                           // 设置操作系统类型
    req.Header.Set("os-version", "")                                           // 设置操作系统版本(这里为空)
    req.Header.Set("priority", "u=1, i")                                       // 设置请求优先级
    req.Header.Set("referer", "https://fanyi.caiyunapp.com/")                 // 设置引用页(Referer)
    req.Header.Set("sec-ch-ua", `"Chromium";v="128", "Not;A=Brand";v="24", "Microsoft Edge";v="128"`) // 设置浏览器用户代理字符串
    req.Header.Set("sec-ch-ua-mobile", "?0")                                   // 设置是否为移动设备
    req.Header.Set("sec-ch-ua-platform", `"Windows"`)                          // 设置平台信息
    req.Header.Set("sec-fetch-dest", "empty")                                  // 设置请求的目的地
    req.Header.Set("sec-fetch-mode", "cors")                                   // 设置请求的模式
    req.Header.Set("sec-fetch-site", "cross-site")                             // 设置请求的站点关系
    req.Header.Set("user-agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36 Edg/128.0.0.0") // 设置用户代理字符串
    req.Header.Set("x-authorization", "token:qgemv4jr1y38jyq6vhvi")           // 设置自定义授权令牌,token// 发送请求
    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)
}
​

在 vscode 或 goland 运行代码结果为:

{"rc":0,"wiki":{},"dictionary":{"prons":{"en-us":"[t\u0251m]","en":"[t\u0254m]"},"explanations":["n.\u96c4\u6027\u52a8\u7269,\u96c4\u732b"],"synonym":[],"antonym":[],"wqx_example":[],"entry":"tom","type":"word","related":[],"source":"wenquxing"}}
​

发现与要爬取的响应一致

并且通过更改 var data = strings.NewReader({"trans_type":"en2zh","source":"tom"}) 中的 source,可以更改要翻译的字符

`var data = strings.NewReader(`{"trans_type":"en2zh","source":"Jerry"}`)` // 更改要查询的文字内容为 Jerry

运行结果

{"rc":0,"wiki":{},"dictionary":{"prons":{"en-us":"[\u02c8d\u0292\u03b5r\u026a]","en":"[\u02c8d\u0292eri]"},"explanations":["n.\u6770\u745e(\u7537\u5b50\u540d)","[\u4fda]\u5fb7\u56fd\u58eb\u5175;\u5fb7\u56fd\u4eba"],"synonym":[],"antonym":[],"wqx_example":[],"entry":"Jerry","type":"word","related":[],"source":"wenquxing"}}

优化代码

观察输入和输出,可以发现请求的负载和响应的内容都是一个json格式的字符串,所以通过构造json结构体简化输入和输出,优化代码

点击dict的响应

image.png

复制内容到JSON转Golang Struct - 在线工具 - OKTools (iokde.com),进行生成,选择 转换-嵌套

image.png

获取生成结构体

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 []interface{} `json:"synonym"`
        Antonym []interface{} `json:"antonym"`
        WqxExample []interface{} `json:"wqx_example"`
        Entry string `json:"entry"`
        Type string `json:"type"`
        Related []interface{} `json:"related"`
        Source string `json:"source"`
    } `json:"dictionary"`
}

同理获取请求负载的结构体

image.png

type AutoGenerated struct {
    TransType string `json:"trans_type"`
    Source string `json:"source"`
}

更改结构体名字

type DictRequest struct {
    TransType string `json:"trans_type"`
    Source    string `json:"source"`
}
​
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      []interface{} `json:"synonym"`
        Antonym      []interface{} `json:"antonym"`
        WqxExample   []interface{} `json:"wqx_example"`
        Entry        string        `json:"entry"`
        Type         string        `json:"type"`
        Related      []interface{} `json:"related"`
        Source       string        `json:"source"`
    } `json:"dictionary"`
}

使用上面的结构体,并进行基本封装,将主要查询封装成函数query,输入则在函数main

package main
​
import (
    "bytes"
    "encoding/json"
    "fmt"
    "io/ioutil"
    "log"
    "net/http"
    "os"
)
​
// DictRequest 定义了发送到彩云翻译的请求结构
type DictRequest struct {
    TransType string `json:"trans_type"` // 翻译类型,例如 "en2zh" 表示从英语到中文
    Source    string `json:"source"`     // 要翻译的源文本
}
​
// DictResponse 定义了从彩云翻译接收的响应结构
type DictResponse struct {
    Rc   int `json:"rc"` // 响应代码,用于指示请求是否成功
    Wiki struct {
    } `json:"wiki"` // Wiki字段,可能包含与单词相关的维基百科信息// Dictionary字段包含了单词的详细解释信息
    Dictionary struct {
        Prons struct {
            EnUs string `json:"en-us"` // 美式发音
            En   string `json:"en"`    // 英式发音
        } `json:"prons"`
        Explanations []string      `json:"explanations"` // 单词解释列表
        Synonym      []interface{} `json:"synonym"`      // 同义词列表
        Antonym      []interface{} `json:"antonym"`      // 反义词列表
        WqxExample   []interface{} `json:"wqx_example"`  // 示例句子列表
        Entry        string        `json:"entry"`        // 单词本身
        Type         string        `json:"type"`         // 单词类型(如名词、动词等)
        Related      []interface{} `json:"related"`      // 相关词汇列表
        Source       string        `json:"source"`       // 解释来源
    } `json:"dictionary"`
}
​
// query函数用于查询指定单词的翻译和解释
func query(word string) {
    client := &http.Client{} // 创建HTTP客户端// 构造请求结构体
    request := DictRequest{TransType: "en2zh", Source: word}
    buf, err := json.Marshal(request) // 将请求结构体序列化为JSON
    if err != nil {
        log.Fatal(err) // 如果序列化失败,记录错误并退出
    }
​
    // 创建新的HTTP请求
    var data = bytes.NewReader(buf) // 将JSON数据转换为io.Reader
    req, err := http.NewRequest("POST", "https://api.interpreter.caiyunai.com/v1/dict", data)
    if err != nil {
        log.Fatal(err) // 如果创建请求失败,记录错误并退出
    }
​
    // 设置HTTP请求头
    req.Header.Set("accept", "application/json, text/plain, */*")
    req.Header.Set("accept-language", "zh")
    req.Header.Set("app-name", "xiaoyi")
    req.Header.Set("authorization", "Bearer")
    req.Header.Set("content-type", "application/json;charset=UTF-8")
    req.Header.Set("device-id", "b7feaa2827a466315abeb73e554ba173")
    req.Header.Set("origin", "https://fanyi.caiyunapp.com")
    req.Header.Set("os-type", "web")
    req.Header.Set("os-version", "")
    req.Header.Set("priority", "u=1, i")
    req.Header.Set("referer", "https://fanyi.caiyunapp.com/")
    req.Header.Set("sec-ch-ua", `"Chromium";v="128", "Not;A=Brand";v="24", "Microsoft Edge";v="128"`)
    req.Header.Set("sec-ch-ua-mobile", "?0")
    req.Header.Set("sec-ch-ua-platform", `"Windows"`)
    req.Header.Set("sec-fetch-dest", "empty")
    req.Header.Set("sec-fetch-mode", "cors")
    req.Header.Set("sec-fetch-site", "cross-site")
    req.Header.Set("user-agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36 Edg/128.0.0.0")
    req.Header.Set("x-authorization", "token:qgemv4jr1y38jyq6vhvi")
​
    // 发送HTTP请求
    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) // 如果读取失败,记录错误并退出
    }
​
    // 检查HTTP状态码
    if resp.StatusCode != 200 {
        log.Fatal("bad StatusCode:", resp.StatusCode, "body", string(bodyText))
    }
​
    // 将响应体中的JSON数据反序列化到DictResponse结构体中
    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) // 打印每个解释
    }
}
​
// main函数是程序的入口点
func main() {
    // 检查命令行参数数量是否正确
    if len(os.Args) != 2 {
        // 如果参数数量不正确,打印使用方法并退出
        fmt.Fprintf(os.Stderr, `usage: simpleDict WORD
example: simpleDict hello
        `)
        os.Exit(1) // 退出程序,返回错误码1
    }
    word := os.Args[1] // 获取要查询的单词
    query(word)        // 调用query函数查询单词
}
​

通过在命令行输入指令运行

PS G:\GoStudy> go run main.go tom

结果

tom UK: [tɔm] US: [tɑm]
n.雄性动物,雄猫

更换翻译网站为:火山翻译

跟上面彩云翻译的步骤大部分一致,但是其中查找相关的ajax请求有点麻烦

image.png

因为有许多前缀相同的ajax请求,需要点击响应,根据时间进行查找

image.png

然后重复上面步骤,得到go代码,其中更改words可以改变要查的单词

package main
​
import (
    "fmt"
    "io"
    "log"
    "net/http"
    "strings"
)func main() {
    client := &http.Client{}
    // 更改 words 后面的值,可以改变要查询的单词
    var data = strings.NewReader(`{"source":"youdao","words":["milk"],"source_language":"en","target_language":"zh"}`)
    req, err := http.NewRequest("POST", "https://translate.volcengine.com/web/dict/detail/v1/?msToken=&X-Bogus=DFSzswVLQDVmHKA/tsxyD5TQh4CK&_signature=_02B4Z6wo00001M8G2cwAAIDBEF0qgR0wjaTPBt1AAFTt8XJzCW7GF0cRJMGx5Zz41ixEjtMtGWj3QFqbP5RqADkyxbn9ziMeRoEXSIXCwGaV91dBwiJ78OjBxhehtNuk7oPBYEDaCE-DPx3m32", data)
    if err != nil {
        log.Fatal(err)
    }
    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("Connection", "keep-alive")
    req.Header.Set("Content-Type", "application/json")
    req.Header.Set("Cookie", "i18next=zh-CN; s_v_web_id=verify_m33ucjvy_9nOqXMPH_Fz81_4KlX_AmuB_lzvdSeet2UsA; ttcid=79cdc8e608df48569bde51b3676dee1378; tt_scid=hcd24O6gTJ0On61Xtinp5k7FnU5IwSTQ5xulXThhPTObP-yu-mI-mbXARDbiXhvi15b0")
    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=milk")
    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 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36 Edg/128.0.0.0")
    req.Header.Set("sec-ch-ua", `"Chromium";v="128", "Not;A=Brand";v="24", "Microsoft Edge";v="128"`)
    req.Header.Set("sec-ch-ua-mobile", "?0")
    req.Header.Set("sec-ch-ua-platform", `"Windows"`)
    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)
}

类似上面彩云翻译,使用结构体优化代码,并进行简单封装 同时,因为响应的 Details 参数过多,所以又编写了另一个结构体ParasResponse来格式化 Details 参数,便于处理

package main
​
import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "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 ParasResponse struct {
    ErrorCode string `json:"errorCode"`
    Msg       string `json:"msg"`
    RequestID string `json:"requestId"`
    Result    []struct {
        Ec struct {
            Basic struct {
                ExamType []string `json:"examType"`
                Explains []struct {
                    Pos   string `json:"pos"`
                    Trans string `json:"trans"`
                } `json:"explains"`
                Phonetic    string `json:"phonetic"`
                UkPhonetic  string `json:"ukPhonetic"`
                UkSpeech    string `json:"ukSpeech"`
                UsPhonetic  string `json:"usPhonetic"`
                UsSpeech    string `json:"usSpeech"`
                WordFormats []struct {
                    Name  string `json:"name"`
                    Value string `json:"value"`
                } `json:"wordFormats"`
            } `json:"basic"`
            Dict      string `json:"dict"`
            Etymology struct {
                ZhCHS []struct {
                    Description string `json:"description"`
                    Detail      string `json:"detail"`
                    Source      string `json:"source"`
                } `json:"zh-CHS"`
            } `json:"etymology"`
            ExplainWithSentences []struct {
                Explain            string `json:"explain"`
                Proportion         string `json:"proportion"`
                SentenceSampleList []struct {
                    Sentence     string `json:"sentence"`
                    SentenceBold string `json:"sentenceBold"`
                    Source       string `json:"source"`
                    Translation  string `json:"translation"`
                } `json:"sentenceSampleList"`
            } `json:"explainWithSentences"`
            IsWord        bool   `json:"isWord"`
            Lang          string `json:"lang"`
            MTerminalDict string `json:"mTerminalDict"`
            Phrases       []struct {
                Meanings []string `json:"meanings"`
                Phrase   string   `json:"phrase"`
            } `json:"phrases"`
            RelWord struct {
                Rels []struct {
                    Rel struct {
                        Pos   string `json:"pos"`
                        Words []struct {
                            Tran string `json:"tran"`
                            Word string `json:"word"`
                        } `json:"words"`
                    } `json:"rel"`
                } `json:"rels"`
                Stem string `json:"stem"`
                Word string `json:"word"`
            } `json:"relWord"`
            ReturnPhrase   []string `json:"returnPhrase"`
            SentenceSample []struct {
                Sentence     string `json:"sentence"`
                SentenceBold string `json:"sentenceBold"`
                Source       string `json:"source"`
                Translation  string `json:"translation"`
            } `json:"sentenceSample"`
            Synonyms []struct {
                Pos   string   `json:"pos"`
                Trans string   `json:"trans"`
                Words []string `json:"words"`
            } `json:"synonyms"`
            Web []struct {
                Meanings []string `json:"meanings"`
                Phrase   string   `json:"phrase"`
            } `json:"web"`
            WebDict string `json:"webDict"`
        } `json:"ec"`
    } `json:"result"`
    UpdatedAt int `json:"updated_at"`
}
​
func query(word string) {
    client := &http.Client{}
    request := DictRequest{Source: "youdao", Words: []string{word}, 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=DFSzswVLQDVmHKA/tsxyD5TQh4CK&_signature=_02B4Z6wo00001M8G2cwAAIDBEF0qgR0wjaTPBt1AAFTt8XJzCW7GF0cRJMGx5Zz41ixEjtMtGWj3QFqbP5RqADkyxbn9ziMeRoEXSIXCwGaV91dBwiJ78OjBxhehtNuk7oPBYEDaCE-DPx3m32", data)
    if err != nil {
        log.Fatal(err)
    }
    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("Connection", "keep-alive")
    req.Header.Set("Content-Type", "application/json")
    req.Header.Set("Cookie", "i18next=zh-CN; s_v_web_id=verify_m33ucjvy_9nOqXMPH_Fz81_4KlX_AmuB_lzvdSeet2UsA; ttcid=79cdc8e608df48569bde51b3676dee1378; tt_scid=hcd24O6gTJ0On61Xtinp5k7FnU5IwSTQ5xulXThhPTObP-yu-mI-mbXARDbiXhvi15b0")
    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=milk")
    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 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36 Edg/128.0.0.0")
    req.Header.Set("sec-ch-ua", `"Chromium";v="128", "Not;A=Brand";v="24", "Microsoft Edge";v="128"`)
    req.Header.Set("sec-ch-ua-mobile", "?0")
    req.Header.Set("sec-ch-ua-platform", `"Windows"`)
    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)
    }
    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)
    }
    var parasResponse ParasResponse
    err = json.Unmarshal([]byte(dictResponse.Details[0].Detail), &parasResponse)
    if err != nil {
        log.Fatal(err)
    }
    for _, explaination := range parasResponse.Result[0].Ec.Synonyms {
        fmt.Println(explaination.Pos, explaination.Trans)
    }
}
​
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)
}
​

使用命令行查询单词 good

PS G:\GoStudy> go run main.go good

结果为:

adj. 好的;优良的;愉快的;虔诚的
n. 好处;善行;慷慨的行为
adv. 好