【GO】go语言入门实战 —— 命令行在线词典

文章目录

      • 程序介绍
      • 抓包
      • 代码生成
      • 生成request body
      • 解析respond body
      • 完整代码

字节青训营基础班学习记录。

程序介绍

在运行程序的时候以命令行的形式输入要查询的单词,然后程序返回单词的音标、释义等信息。

示例如下:

image-20230727001201922

抓包

我们选择与网站https://fanyi.caiyunapp.com/建立连接。

首先我们打开网站,Windows下直接按f12进入开发者工具,

然后输入一个单词并点击翻译按钮,在网络tag部分找到请求方法为POSTdict

image-20230727012140182

这里有部分请求表头,是我们后续需要在代码中添加设置的。

然后去负载tag可以看到这次请求的source也就是要翻译的单词,

也能看到要翻译的类型,这里是en2zh,也就是英文到中文:

image-20230727011353343

这个请求是JSON类型的,我们后续存储会用结构体去存储这个数据,所以传请求信息的时候要先对结构体进行序列化。

预览tag就是这次请求返回的信息:

image-20230727011745206

返回信息也是JSON,为了方便打印我们后续也会将返回得到的JSON反序列化存放到对应的结构体变量中。


代码生成

我们要实现一个在线词典,所以我们运行程序后需要程序发送对应的请求。

上面也看了,部分代码会特别复杂,

所以这里用到一个代码生成工具Convert curl to Go (curlconverter.com)帮我们完成部分代码工作。

鼠标指向刚刚的请求tag -> 右键点击 -> 选择复制 -> 选择复制为cURL(cmd)

image-20230727012635552

然后将我们复制后的信息粘贴到网站的curl command下面的代码框内得到生成的go语言代码:

此时可能会出现这样的报错信息:

image-20230727012917891

这是因为我们复制的command的每一行是以^结尾的,我们需要手动改成\,这样就没问题了:

image-20230727013050378

然后把代码复制到我们的代码编辑器中就OK了。

下面添加了部分注释帮助理解代码:

package main

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

func main() {
    //创建http客户端
	client := &http.Client{}
    
    //data是请求参数,也就是翻译类型和要翻译的单词
    //由于创建请求信息的时候请求参数是io.Reader流类型
    //所以需要用strings.NewReader()将JSON转化为io.Reader类型
	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("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("app-name", "xy")
	req.Header.Set("content-type", "application/json;charset=UTF-8")
	req.Header.Set("device-id", "dde0d0432ca66c7fe6175b7bf940b7f2")
	req.Header.Set("origin", "https://fanyi.caiyunapp.com")
	req.Header.Set("os-type", "web")
	req.Header.Set("os-version", "")
	req.Header.Set("referer", "https://fanyi.caiyunapp.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", "?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/115.0.0.0 Safari/537.36 Edg/115.0.1901.183")
	req.Header.Set("x-authorization", "token:qgemv4jr1y38jyq6vhvi")
    
    //发送请求
	resp, err := client.Do(req)
	if err != nil {
		log.Fatal(err)
	}
    
	//成功拿到请求后关闭请求,如果不关闭请求可能会造成资源泄漏
	//defer关键字会在函数结束时调用resp.Body.Close()方法
	defer resp.Body.Close()
    
	//读取请求返回的数据
	//这里使用ioutil.ReadAll()方法读取,返回的是[]byte类型的数据
	bodyText, err := io.ReadAll(resp.Body)
	if err != nil {
		log.Fatal(err)
	}
    
    //打印返回的信息
	fmt.Printf("%s\n", bodyText)
}

生成request body

上面的代码已经能够成功发送请求并接收序列化的返回信息。

但是现在有一个缺点,请求信息是一个写死的JSON转成的流,

而我们需要从命令行自己输入单词,而单词又是请求信息的一部分,

所以我们需要定义一个能存放请求信息的结构体,结构体核心字段为trans_typesource

image-20230728192141308

我们是要从命令行中获取要翻译的单词,

所以可以从命令行参数中读取单词并用其初始化我们要创建的请求信息结构体变量,

trans_type字段是我们要翻译的类型,需要初始化为en2zh

这样就可以用结构体来表示我们的请求信息。

但是发送请求时请求信息需要转为io.Reader类型,

所以我们还需要先将结构体序列化,

然后使用func bytes.NewReader(b []byte) *bytes.Reader将序列化后的JSON转成io.Reader类型,

之后就可以创建请求。

// DictRequest 请求参数
// 因为需要序列化,所以结构体每个字段的首字母都要大写
type DictRequest struct {
	TransType string `json:"trans_type"`
	Source    string `json:"source"`
	UserID    string `json:"user_id"`
}

//读取命令行参数,也就是我们要翻译的单词
word := os.Args[1]
//用我们读到的单词初始化请求信息结构体
request := DictRequest{TransType: "en2zh", Source: word}  

//将结构体序列化为json字符串
buf, err := json.Marshal(request)
if err != nil {
    log.Fatal(err)
}

//将json字符串转换为io.Reader类型,因为NewRequest()方法需要传入io.Reader类型的参数
var data = bytes.NewReader(buf)
req, err := http.NewRequest("POST", "https://api.interpreter.caiyunai.com/v1/dict", data)
if err != nil {
    log.Fatal(err)
}

解析respond body

此时我们的程序已经可以翻译单个从命令行输入的单词,

并接收全部的返回信息:

image-20230727193757711

请求返回的信息是JSON序列,

而我们需要把这些信息反序列到一个结构体中,

然后打印出结构体中我们想要的部分信息。

所以我们还需要定义一个结构体用以接收返回信息反序列化的结果。

而返回信息中有太多字段了,一一去定义这些字段不仅低效并且容易出错,

所以这里使用到了另一款工具:JSON转Golang Struct - 在线工具 - OKTools。

首先还是打开开发者工具,找到POST请求,点击预览:

image-20230728192622648

然后单击鼠标右键选择复制值。

随后进入上面那个网站,将复制的内容 粘贴在左边一栏,然后点击转换嵌套:

image-20230728192901614

这样就得到了对应的接收返回信息的结构体类型。

现在就可以把这段代码改个结构体的名添加到我们的代码中:

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"`
}

此前代码生成部分接收的返回数据是以[]byte类型在bodyTest中存储的,

此时我们就可以将其反序列化为结构体对象,

然后选择性地打印我们所需要的字段:

//将返回的数据反序列化解析到结构体中
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函数中读取待翻译的单词,

然后将发送请求到接受返回信息并打印这一部分封装成query函数,

将待翻译的单词作为参数,

如果有多个待翻译的单词可以在main函数中一个个读取并调用query函数 :

package main

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

// DictRequest 请求参数
type DictRequest struct {
	TransType string `json:"trans_type"`
	Source    string `json:"source"`
	UserID    string `json:"user_id"`
}

// DictResponse 返回参数
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) {
	//创建http客户端
	client := &http.Client{}

	//创建请求
	//POST请求,需要传入请求方法,请求地址,请求参数
	//这里的地址是我自己搭建的一个测试接口,大家可以自行搭建或者使用其他接口
	//data是请求参数,需要使用strings.NewReader()方法转换为io.Reader类型
	request := DictRequest{TransType: "en2zh", Source: word}

	//将结构体序列化为json字符串
	buf, err := json.Marshal(request)
	if err != nil {
		log.Fatal(err)
	}

	//将json字符串转换为io.Reader类型,因为NewRequest()方法需要传入io.Reader类型的参数
	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()方法
	defer resp.Body.Close()

	//读取请求返回的数据
	//这里使用ioutil.ReadAll()方法读取,返回的是[]byte类型的数据
	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 os.Args == nil || len(os.Args) < 2 {
		fmt.Fprintf(os.Stderr, "usage: simpleDict WORDexample: simpleDict hello")
		os.Exit(1)
	}

	for _, word := range os.Args[1:] {
		query(word)
		fmt.Println()  //每打印完一个单词的信息用空行隔开
	}
}

至此就完成了一个 简单的命令行在线词典。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/57366.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Docker Compose 使用方法

目录 前言 安装 Docker Compose Ubuntu 安装与更新 Red Hat 安装与更新 验证是否安装 Docker Compose 创建 docker-compose.yml 文件 创建一个MySQL 与 tomcat 示例 使用Docker Compose启动服务 前言 Docker Compose 是一个工具&#xff0c;旨在帮助定义和 共享多容器…

Vue如何做一个左边栏

要求一-------点击之后能够实现页面跳转,使用router&#xff0c;点击之后跳到指定页面&#xff1a; 第二步&#xff1a;如何实现简易的前端路由 第三步 左侧边栏的正确写法&#xff0c;ul中li套router-link 第四步 实现嵌套路由 第五步 ul中嵌套着li 第六步嵌套路由 第七步&…

Navidrome - 开源音乐服务器【打造属于自己的音乐播放器】「端口映射」随时随地想听就听

转载自cpolar极点云文章&#xff1a;Navidrome - 开源音乐服务器【打造属于自己的音乐播放器】「端口映射」随时随地想听就听 1. 前言 不知从何时开始&#xff0c;我们能用的音乐软件越来越少&#xff0c;笔者使用小米手机很久了&#xff0c;自从小米手机的自带音乐播放器变成…

MIAOYUN获评“2023年度一云多芯稳定安全运行优秀案例”

2023年7月25日至26日&#xff0c;由中国信息通信研究院&#xff08;简称“中国信通院”&#xff09;、中国通信标准化协会主办的以“云领创新&#xff0c;算启新篇”为主题的“2023可信云大会”在北京成功举办。会上公布了多项前瞻领域的评估结果和2023年度最佳实践案例&#x…

浅析视频技术与AI智能感知与生鲜供应链的数字化应用

一、行业背景 近年来&#xff0c;我国肉类、水果、蔬菜、水产品、乳品、速冻食品等生鲜市场需求快速增长&#xff0c;营商环境持续改善&#xff0c;推动冷链物流较快发展&#xff0c;但仍面临不少突出瓶颈和痛点难点卡点问题&#xff0c;难以有效满足市场需求。传统生鲜食材供…

公司植物日常护养方法备忘录

植物为我们净化空气&#xff0c;美化环境&#xff0c;我们要按照科学的经验照顾好它们。公司植物日常通用护养方法如下&#xff1a; 首先剪掉已经枯黄的部分。 需要晒太阳的植物按时搬到外面晒太阳&#xff0c;每次晒1到2个小时。 所有植物统一在每个月的20号左右施肥一次&am…

docker logs 使用说明

docker logs 可以查看某个容器内的日志情况。 前置参数说明 c_name容器名称 / 容器ID logs 获取容器的日志 , 命令如下&#xff1a; docker logs [options] c_name option参数&#xff1a; -n 查看最近多少条记录&#xff1a;docker logs -n 5 c_name--tail与-n 一样 &#…

如何编写一个易于维护的考试系统源码

编写一个易于维护的考试系统源码对于开发人员来说非常重要。一个易于维护的系统可以使代码更易于理解、修改和扩展&#xff0c;从而提高开发效率和系统稳定性。 第一步&#xff1a;良好的项目结构 良好的项目结构是一个易于维护的源码的基础。可以按照模块、功能或层次等方式…

C++初阶 - 6.模板初阶

目录 1.泛型编程 2.函数模板 2.1函数模板的概念 2.2函数模板格式 2.3 函数模板的原理 2.4 函数模板的实例化 2.5模板参数的匹配原则 3.类模板 3.1类模板的定义格式 3.2类模板的实例化 1.泛型编程 如何实现一个通用的交换函数呢&#xff1f; void Swap(int& left…

LeetCode 626. 换座位

题目链接&#xff1a;LeetCode 626. 换座位 题目描述 表名&#xff1a;Seat 编写SQL查询来交换每两个连续的学生的座位号。如果学生的数量是奇数&#xff0c;则最后一个学生的id不交换。 按 id 升序 返回结果表。 查询结果格式如下所示。 示例1&#xff1a; 题目分析 如…

java后端富文本转word,再传递到浏览器下载。

思路参考&#xff0c;以及所有的工具类都使用了》牧羊人大佬的代码《 有帮助的话不用给到我点赞&#xff0c;给大佬点赞即可 这是前端代码&#xff0c;必须使用get。 post后端返回的流浏览器接收不到&#xff08;具体原因不详&#xff09;。get无法传递requestBody&#xff0c;…

Json文件编辑功能

1 Json格式 JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式。它基于 ECMAScript&#xff08;European Computer Manufacturers Association, 欧洲计算机协会制定的js规范&#xff09;的一个子集&#xff0c;采用完全独立于编程语言的文本格式来存储和表示数据。…

Java-多态

目录 1.多态的概念 2.多态的实现条件。 3.重写 4.向上转型和向下转型 5.多态的优缺点 6.避免在构造方法中调用重写方法 1.多态的概念 多态字面意思就是多种形态&#xff0c;具体点就是完成某个行为时&#xff0c;不同的对象完成时产生不同的状态。 总之&#xff0c;同一件…

uniapp运行项目到iOS基座

2022年9月&#xff0c;因收到苹果公司警告&#xff0c;目前开发者已无法在iOS真机设备使用未签名的标准基座&#xff0c;所以现在要运行到 IOS &#xff0c;也需要进行签名。 Windows系统&#xff0c;HBuilderX 3.6.20以下版本&#xff0c;无法像MacOSX那样对标准基座进行签名…

JavaSE【继承和多态】(2)(向上转型、向下转型、重写、动态绑定、静态绑定、多态的运用)

一、多态 1.多态的概念 多态的概念&#xff1a;通俗来说&#xff0c;就是多种形态&#xff0c; 具体点就是去完成某个行为&#xff0c;当不同的对象去完成时会产生出不同 的状 态。 简单说就是&#xff0c;同一件事情&#xff0c;发生在不同对象身上&#xff0c;就会产生不同…

Mac强制停止应用

有时候使用Mac的时候&#xff0c;某个应用卡住了&#xff0c;但是肯定不能因为一个应用卡住了&#xff0c; 就将电脑重启吧&#xff0c;所以只需要单独停止该应用即可&#xff0c;使用快捷键optioncommandesc就会出现强制停止的界面&#xff0c;选择所要停止的应用&#xff0c;…

如何解决跨域问题?

一&#xff0c;什么是跨域 域&#xff08;Origin&#xff09;是由协议、域名和端口组成的&#xff0c;只有这三者完全一致的情况下&#xff0c;浏览器才会认为两个网址同源&#xff0c;否则就认为存在跨域。跨域是指在Web开发中&#xff0c;一个网页的JavaScript代码试图访问另…

yolov8-制作数据集,数据集格式转换(yolo格式-voc格式)附完整代码

yolo训练时可使用的数据集格式为yolo格式以及voc格式&#xff0c; voc格式的数据集在训练时需要先转换为yolo格式&#xff0c;然后根据自己的数据集的位置更改yaml配置文件的文件路径即可。基于目前对Yolo系列训练模型的讲解已经很全面&#xff0c;所以本文主要讲解yolo数据集与…

aws中opensearch 日志通(Centralized Logging with OpenSearch)2.0(一)

aws日志通2.0 实现全面的日志管理和分析功能 一体化日志摄取 &#xff1a;把aws服务器日志和应用日志传输到opensearch域中无代码日志处理 &#xff1a;在网页控制台中就可以实现数据处理开箱即用 &#xff1a;提供可视化模版&#xff08;nginx、HTTP server &#xff09; 架构…

如何有效保障企业内部网络安全?好的方式是什么?

据统计&#xff0c;70%的数据泄露安全事故来源于企业内部。所以有效保障企业内部网络安全至关重要。但不少企业还不知道如何有效保障企业内部网络安全&#xff1f;也不知道有哪些好的方式&#xff1f;这里我们小编就跟大家来一起简单探讨一下。 什么是网络安全&#xff1f; 网…