【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 mainimport ("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 mainimport ("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 DictResponseerr = 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()  //每打印完一个单词的信息用空行隔开}
}

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

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Linux6.17 Docker 安全及日志管理

文章目录 计算机系统5G云计算第四章 LINUX Docker 安全及日志管理一、Docker 容器与虚拟机的区别1.隔离与共享2.性能与损耗 二、Docker 存在的安全问题1.Docker 自身漏洞2.Docker 源码问题 三、Docker 架构缺陷与安全机制1.容器之间的局域网攻击2.DDoS 攻击耗尽资源3.有漏洞的系…

mac版窗口管理 Magnet for mac中文最新

magnet mac版是一款运行在苹果电脑上的一款优秀的窗口大小控制工具&#xff0c;拖拽窗口到屏幕边缘可以自动半屏&#xff0c;全屏或者四分之一屏幕&#xff0c;还可以设定快捷键完成分屏。这款专业的窗口管理工具当您每次将内容从一个应用移动到另一应用时&#xff0c;当您需要…

【Git】初始化仓库配置与本地仓库提交流程

目录 一、仓库配置邮箱与用户名 二、本地仓库提交流程 一、仓库配置邮箱与用户名 【Git】Linux服务器Centos环境下安装Git与创建本地仓库_centos git仓库搭建_1373i的博客-CSDN博客https://blog.csdn.net/qq_61903414/article/details/131260033?spm1001.2014.3001.5501 在…

物联网网关模块可以带几台plc设备吗?可以接几个modbus设备?

随着物联网技术的快速发展&#xff0c;物联网网关模块已经成为了实现物联网应用的重要工具。很多客户在选择物联网网关模块时想了解物联网网关模块的设备接入能力&#xff0c;一个物联网网关模块可以带几台PLC设备&#xff1f;可以接几个Modbus设备&#xff1f; 物联网网关模块…

目标检测-击穿黑夜的PE-YOLO

前言 当前的目标检测模型在许多基准数据集上取得了良好的结果&#xff0c;但在暗光条件下检测目标仍然是一个巨大的挑战。为了解决这个问题&#xff0c;作者提出了金字塔增强网络&#xff08;PENet&#xff09;并将其与YOLOv3结合&#xff0c;构建了一个名为PE-YOLO的暗光目标检…

前后端分离开发流程

1、介绍 在前后端分离开发中&#xff0c;前端负责用户界面和交互逻辑的实现&#xff0c;后端则处理业务逻辑和数据持久化。这种开发模式的优势在于前后端可以独立进行开发&#xff0c;提高了开发效率&#xff0c;并且使得前后端可以采用不同的技术栈来实现各自的功能。 2、开…

基于Vue3实现鼠标按下某个元素进行移动,实时改变左侧或右侧元素的宽度,以及点击收起或展开的功能

其原理主要是利用JavaScript中的鼠标事件来控制CSS样式。大致就是监听某个DOM元素的鼠标按下事件&#xff0c;以及按下之后的移动事件和松开事件。在鼠标按下且移动过程中&#xff0c;可实时获得鼠标的X轴坐标的值&#xff0c;通过简单计算&#xff0c;可计算出目标元素的宽度&…

八、Kafka时间轮与常见问题

Kafka与时间轮 Kafka中存在大量的延时操作。 1、发送消息-超时重试机制 2、ACKS 用于指定分区中必须要有多少副本收到这条消息&#xff0c;生产者才认为写入成功&#xff08;延时 等&#xff09; Kafka并没有使用JDK自带的Timer或者DelayQueue来实现延迟的功能&#xff0c;而…

石子合并(区间dp模板)

题目描述&#xff1a; dp分析&#xff1a; 解题代码&#xff1a; #include<iostream> using namespace std;const int N1e36;int f[N][N]; int a[N]; int s[N];int main(){int n;cin>>n;for(int i1;i<n;i){scanf("%d",&s[i]);s[i]s[i-1];//前缀和…

谈谈你对Synchronized关键字的理解及使用

synchronized关键字最主要的三种使用方式的总结 修饰实例方法&#xff0c;作用于当前对象实例加锁&#xff0c;进入同步代码前要获得当前对象实例的锁修饰静态方法&#xff0c;作用于当前类对象加锁&#xff0c;进入同步代码前要获得当前类对象的锁 。也就是给当前类加锁&…

centos7安装tomcat

安装tomcat 必须依赖 JDK 环境&#xff0c;一定要提前装好JDK保证可以使用 一、下载安装包 到官网下载 上传到linux 服务器 二、安装tomcat 创建tomcat 文件夹 mkdir -p /usr/local/tomcat设置文件夹权限 chmod 757 tomcat将安装包上传至 新建文件夹 解压安装包 tar zx…

自动驾驶之轨迹规划8——Apollo参考线和轨迹

1. abstract 本文主要讲解routing和planning模块中的reference line&#xff0c;我之前一直搞不明白这个reference line是如何生成的&#xff0c;有什么作用&#xff0c;和routing以及planning的关系。现在有了一些心得打算梳理一下&#xff1a; 决策规划模块负责生成车辆的行…

浅谈3D隐式表示(SDF,Occupancy field,NeRF)

本篇文章介绍了符号距离函数Signed Distance Funciton(SDF)&#xff0c;占用场Occupancy Field&#xff0c;神经辐射场Neural Radiance Field&#xff08;NeRF&#xff09;的概念、联系与区别。 显式表示与隐式表示 三维空间的表示形式可以分为显式和隐式。 比较常用的显式表…

STM32 串口基础知识学习

串行/并行通信 串行通信&#xff1a;数据逐位按顺序依次传输。 并行通信&#xff1a;数据各位通过多条线同时传输。 对比 传输速率&#xff1a;串行通信较低&#xff0c;并行通信较高。抗干扰能力&#xff1a;串行通信较强&#xff0c;并行通信较弱。通信距离&#xff1a;串…

区间预测 | MATLAB实现QRLSTM长短期记忆神经网络分位数回归多输入单输出区间预测

区间预测 | MATLAB实现QRLSTM长短期记忆神经网络分位数回归多输入单输出区间预测 目录 区间预测 | MATLAB实现QRLSTM长短期记忆神经网络分位数回归多输入单输出区间预测效果一览基本介绍模型描述程序设计参考资料 效果一览 基本介绍 MATLAB实现QRLSTM长短期记忆神经网络分位数回…

计算机科学cs/电子信息ei面试准备——数学基础/线性代数复习

1. 中值定理 中值定理是反映函数与导数之间联系的重要定理&#xff0c;也是微积分学的理论基础&#xff0c;在许多方面它都有重要的作用&#xff0c;在进行一些公式推导与定理证明中都有很多应用。中值定理是由众多定理共同构建的&#xff0c;其中拉格朗日中值定理是核心&…

【Linux命令200例】less强大的文件内容查看工具

&#x1f3c6;作者简介&#xff0c;黑夜开发者&#xff0c;全栈领域新星创作者✌&#xff0c;2023年6月csdn上海赛道top4。 &#x1f3c6;本文已收录于专栏&#xff1a;Linux命令大全。 &#x1f3c6;本专栏我们会通过具体的系统的命令讲解加上鲜活的实操案例对各个命令进行深入…

最优除法(力扣)数学 JAVA

给定一正整数数组 nums&#xff0c;nums 中的相邻整数将进行浮点除法。例如&#xff0c; [2,3,4] -> 2 / 3 / 4 。 例如&#xff0c;nums [2,3,4]&#xff0c;我们将求表达式的值 “2/3/4”。 但是&#xff0c;你可以在任意位置添加任意数目的括号&#xff0c;来改变算数的…

苍穹外卖day07——缓存菜品套餐+购物车功能实现

缓存菜品——需求设计与分析 问题说明 用户访问量过大带来的一个直接效果就是响应速度慢&#xff0c;使用体验下降。 实现思路 使用redis缓存菜品数据&#xff0c;减少数据库查询操作。 页面展示上基本就是同一个分类在同一页&#xff0c;所以key-value结构可以使用不同的分…

【Git】版本回退与撤销修改案例

目录 一、版本回退 二、撤销修改案例 案例1&#xff1a;仅在工作区进行了修改还未进行add操作 案例2&#xff1a;仅进行了add 操作还未进行commit操作 案例3&#xff1a;进行了add与commit操作无其他操作 三、版本库中删除文件 一、版本回退 在进行版本回退之前我们需要…