青训营Day1作业 | 青训营笔记

220 阅读5分钟

这是我参与「第五届青训营 」伴学笔记创作活动的第 1 天

课程总结

  1. 学习了 Go 的基础语法,包括多种变量定义方式、流程控制、数组切片、Map、结构体、异常处理、字符串、Json、Time、命令行等等。
  2. 掌握 Go 语言中关于随机数生成、控制台输入输出流等技巧。
  3. 掌握 Go 中通过 Http 请求获取相应内容,并将其反序列化为 Go 结构体的方法。
  4. 掌握 Go 搭建简单代理服务器的方法。

作业

猜谜游戏

一些重点:

  1. 使用 math/rand 包中的 rand 时,需要提前指定随机数种子,不然每次运行时产生的随机数固定。

    1. 随机种子赋值可以用运行时的时间戳,详见代码
  2. 关于 bufio,它设置了一个输入输出缓冲区来加快速度,避免对底层存储系统的多次访问。更深层次的原理可以参考:juejin.cn/post/705826…

  3. 关于 fmt.Scanf 的使用可以参考:blog.csdn.net/putyourhear…

下面附上作业,使用 scanf 代替 bufio 后的代码:

package main

import (
    "fmt"
    "math/rand"
    "time"
)

func main() {
    maxNum := 100
    rand.Seed(time.Now().UnixNano())
    secretNumber := rand.Intn(maxNum)

    fmt.Println("Please input your guess")
    for {
        guess := 0
        _, err := fmt.Scanf("%d", &guess)
        if err != nil {
            fmt.Println("An error occured while reading input. Please try again", err)
            continue         }
        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         
        }
    }
}

在线词典

  • F12 查看 API,复制为 curl 命令,到 Convert 转换为 Go 代码
  • 复制 response 信息,到 oktools 中将 Json 转为 Go 结构体

作业一,添加了百度翻译作为第二翻译引擎支持。

作业二,使用 channel 来同步两个协程,只要其中有一个协程写入 channel,则另一个不再打印结果。这样就可以取最快的请求返回结果。

具体实现过程中,由于百度翻译 API 中的 sign 值是前端生成的,具体算法比较复杂,所以这里无法只根据查询单词内容返回结果,这里就没再深究了,如果使用 Python 爬取的话,有已经写好的库可以用:blog.csdn.net/qq_30162859…

package main

import (
        "bytes"
        "encoding/json"
        "fmt"
        "io/ioutil"
        "log"
        "net/http"
        "os"
        "strings"
)

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 {
                KnownInLaguages int `json:"known_in_laguages"`
                Description     struct {
                        Source string      `json:"source"`
                        Target interface{} `json:"target"`
                } `json:"description"`
                ID   string `json:"id"`
                Item struct {
                        Source string `json:"source"`
                        Target string `json:"target"`
                } `json:"item"`
                ImageURL  string `json:"image_url"`
                IsSubject string `json:"is_subject"`
                Sitelink  string `json:"sitelink"`
        } `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"`
}

type BaiduDictResponse struct {
        DictResult struct {
                SimpleMeans struct {
                        WordName  string   `json:"word_name"`
                        From      string   `json:"from"`
                        WordMeans []string `json:"word_means"`
                        Exchange  struct {
                                WordPl  []string `json:"word_pl"`
                                WordEst []string `json:"word_est"`
                                WordEr  []string `json:"word_er"`
                        } `json:"exchange"`
                        Tags struct {
                                Core  []string `json:"core"`
                                Other []string `json:"other"`
                        } `json:"tags"`
                        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"`
                Lang string `json:"lang"`
        } `json:"dict_result"`
}

func query(word string, c chan int) {
        client := &http.Client{}
        // 构造请求 body 结构体,然后序列化为 Json 字符串
        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("Connection", "keep-alive")
        req.Header.Set("DNT", "1")
        req.Header.Set("os-version", "")
        req.Header.Set("sec-ch-ua-mobile", "?0")
        req.Header.Set("User-Agent", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.51 Safari/537.36")
        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", "")
        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")
        req.Header.Set("Cookie", "_ym_uid=16456948721020430059; _ym_d=1645694872")
        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)
        }
        if len(c) == 1 {
                close(c)
                return
        }
        c <- 1

        fmt.Println(word, "UK:", dictResponse.Dictionary.Prons.En, "US:", dictResponse.Dictionary.Prons.EnUs)
        for _, item := range dictResponse.Dictionary.Explanations {
                fmt.Println(item)
        }
}

func query_by_baidu(word string, c chan int) {
        client := &http.Client{}
        var data = strings.NewReader(fmt.Sprintf("from=en&to=zh&query=%v&transtype=enter&simple_means_flag=3&sign=262931.57378&token=a96c5437b49673a096f48b66094903b7&domain=common", word))
        req, err := http.NewRequest("POST", "https://fanyi.baidu.com/v2transapi?from=en&to=zh", data)
        if err != nil {
                log.Fatal(err)
        }
        req.Header.Set("Accept", "*/*")
        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("Acs-Token", "1673769896714_1673781839135_/jNTmMdug05eaCQYNoVx1yA3nMqigRtFMSJAlz/zUNGC0gd2BpH8RupkqxzXZl7hL+rUhzPwH1PJLpRiww9t5nFbOZgfjWkurDnJrk3xr7FZOu0sT2mCiZqzpnxgRTscN50WTaELwA6ls5TBdq1ldPXAt1NyhicAatngXIBG2GnDew9M/Iql+bVI7Hdsumedin1lZeUaXz1CpzTQzqgan9WClE9E0bNWQZjCDEi5lnF3qkfD8XuwNOSNAGeiHcvIOqlGBvOjTZ9v1idYrahoQ3JDBvlZ/4gLOtuZ0xRx8XNEnSE9WEKqMkqbRajkEnsjmsu5z3MGQUkGQ2caJvYJsQ==")
        req.Header.Set("Connection", "keep-alive")
        req.Header.Set("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8")
        req.Header.Set("Cookie", "BAIDUID=8C8906FD9A2F5428E482BA2B3A171413:FG=1; BAIDUID_BFESS=8C8906FD9A2F5428E482BA2B3A171413:FG=1; Hm_lvt_64ecd82404c51e03dc91cb9e8c025574=1673777565; APPGUIDE_10_0_2=1; REALTIME_TRANS_SWITCH=1; FANYI_WORD_SWITCH=1; HISTORY_SWITCH=1; SOUND_SPD_SWITCH=1; SOUND_PREFER_SWITCH=1; Hm_lpvt_64ecd82404c51e03dc91cb9e8c025574=1673781835; ab_sr=1.0.1_Y2RmNDQxNjMzNTM2N2VhMzZiMjMwOTBkNjAxNTVmYzNmYzFmZDlhMGNmNDE0MjkxODY3MmZlYzMxZTM0ZTYzMTg5MGMzMDJkNGE3ZWQyNjgyZTIwZTg2NzdkZDZmZDQ0ZmFhZGY3OWJiOTdjZmY4YmJiY2U0OTYxMzA1Mzg4ZDk4YTEyMjdkZWViZjljMjBiNjczMzk0YjRhOTQ4MWFhMw==")
        req.Header.Set("Origin", "https://fanyi.baidu.com")
        req.Header.Set("Referer", "https://fanyi.baidu.com/")
        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 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36 Edg/108.0.1462.76")
        req.Header.Set("X-Requested-With", "XMLHttpRequest")
        req.Header.Set("sec-ch-ua", `"Not?A_Brand";v="8", "Chromium";v="108", "Microsoft Edge";v="108"`)
        req.Header.Set("sec-ch-ua-mobile", "?0")
        req.Header.Set("sec-ch-ua-platform", `"macOS"`)
        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)
        }
        var dictResponse BaiduDictResponse
        err = json.Unmarshal(bodyText, &dictResponse)
        if err != nil {
                log.Fatal(err)
        }

        if len(c) == 1 {
                close(c)
                return
        }
        c <- 1

        if len(dictResponse.DictResult.SimpleMeans.Symbols) == 0 {
                fmt.Println("Sorry, the word was not found")
                return
        }

        fmt.Println(word, "UK:", dictResponse.DictResult.SimpleMeans.Symbols[0].PhEn, "US:", dictResponse.DictResult.SimpleMeans.Symbols[0].PhAm)
        for _, item := range dictResponse.DictResult.SimpleMeans.Symbols[0].Parts {
                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]

        c := make(chan int, 2)
        go query(word, c)
        go query_by_baidu(word, c)
        <-c
}

参考资料:

  1. Go Channel 详解 | 菜鸟教程 (runoob.com)
  2. Go语言通道(chan)——goroutine之间通信的管道 (biancheng.net)
  3. Convert curl commands to Go (curlconverter.com)
  4. JSON转Golang Struct - 在线工具 - OKTools