基于有道API的命令行词典(golang版)

Godict

本项目地址

近期一直再使用golang语言开发一些工具,相关的后端技术链(golang+orm+postgresql+gin+jwt+logrus)和对应前端的技术链(vue+iview+axios+vue-router)基本已经打通了,项目地址。但是想到除了这一套前后端的东西外,命令行的一些操作也是不可避免的。因此就找到了cobra这个应用广泛的第三方命令行库,并借这个小项目练一下手。

功能

golang天然的带有网络操作的优势,所以直接借用现有的第三方api服务来做一个实用的小工具。首先想到的就是词典翻译,因为这个工具我之前在学习python时就做过一个。

python版本有道词典

既然需要做一个golang版本的有道词典(前期只考虑命令行),那么第一步就需要有翻译接口。

接口获取有两种途径:

  1. 模拟网页请求,然后解析html文本抓取其中的有效结果数据。这就是所谓的爬虫了。

  2. 使用官方指定的api调用接口直接获取数据。

第一种方法方法简单粗暴,没啥限制,但是由于时爬虫解析整个网页,如果网页结构变化了,就容易失效,而且效率也相对较低,毕竟要从一大堆数据中找出一点点有用的东西出来。

第二种方法是官方提供的接口,所以基本是长期有效的,相对很稳定,返回的数据就是json数据,比较简洁,没有多余的无用内容,方便解析。但是每天的访问次数有一定限制。不过个人使用也够用了。

综上所述,我们选择第二种方式来实现。

所以第一个需要使用的库就是golang官方的net/http库了。

有道智云API

网易提供了现有的api,这个api需要先注册,然后获取一个应用的key,同时会生成一个应用的密钥,此处我把这两个东西用appKey和appSecret来表示。至于怎么申请,官方流程会说的很详细

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fRMKkW1f-1580622385490)( https://raw.githubusercontent.com/qiuzhiqian/Godict/master/doc/img/image_1.png)]

API使用方式

api的使用方式需要参考有道智云的官方文档

有道智云官方文档

从文档上我们获取到一下信息:

文本翻译接口地址: https://openapi.youdao.com/api

协议:

规则 描述
传输方式 HTTPS
请求方式 GET/POST
字符编码 统一使用UTF-8 编码
请求格式 表单
响应格式 JSON

表单中的参数:

字段名 类型 含义 必填 备注
q text 待翻译文本 True 必须是UTF-8编码
from text 源语言 True 参考下方 支持语言 (可设置为auto)
to text 目标语言 True 参考下方 支持语言 (可设置为auto)
appKey text 应用ID True 可在 应用管理 查看
salt text UUID True UUID
sign text 签名 True sha256(应用ID+input+salt+curtime+应用密钥)
signType text 签名类型 True v3
curtime text 当前UTC时间戳(秒) true TimeStamp
ext text 翻译结果音频格式,支持mp3 false mp3
voice text 翻译结果发音选择 false 0为女声,1为男声。默认为女声

签名生成方法如下:
signType=v3;
sign=sha256(应用ID+input+salt+curtime+应用密钥);
其中,input的计算方式为:input=q前10个字符 + q长度 + q后10个字符(当q长度大于20)或 input=q字符串(当q长度小于等于20);

好了,到了这一步基本的一些操作信息就都有了

我们来逐个分析一下参数:

q

就是需要翻译的文本

from to

就是从什么语言翻译成什么语言,对应语言的格式官方文档有详细列表。

appKey

这个就是上面提到的在有道智云申请的弄个东西了。

salt

是一个uuid,所以我们需要一个用来生成uuid的库,golang有第三方uuid库。

sign

这个就是最关键的东西,前面,这个需要根据前面的这些信息来计算出来,计算公式上面提到了。

signType

这个固定位v3就行

准备数据

通过上面的分析,可以知道我们需要准备一下数据:

待翻译的单词(word),uuid,源语言(fromLan),目标语言(toLan),appKey,appSecret,sign,signType

我们先考虑一下整个app的工作流程:

鉴于appKey和appSecret是比较私密的东西,所以应该放到配置文件中来让用户配置自己对应的appKey和appSecret,而不应该把这两部分在程序中写死。所以我们需要加载一个配置文件,暂定为应用同级目录下的config.json。

带翻译的单词、源语言和目标语言这个应该是由用户来输入的,所以需要有一个命令行传参,我们借用cobra。

uuid需要在应用程序内实时生成

sign需要根据已知变量来计算,signType固定值


cobra

cobra是一个构建命令行工具的库,我们先大致描述一下我们需要的命令结构,首先word是必须的,还要附加两个标志(flag):from和to。

所以大概就是这个样子:

$ ./appname word --from en --to zh-CSH

或者简写成

$ ./appname word -f en -t zh-CSH

cobra中的命令组织方式是一个树状的方式,首先有一个根命令,根命令中添加若干个子命令,然后每个子命令又可以添加自己的子命令。

所处cobra中,最基本的单元就是命令(cobra.Command),命令之间可以添加父子关系,最后组织成一个命令树。

每个命令有基本的5个成员:

  • Use 用来描述命令的使用方式
  • Short 命令的简短帮助信息
  • Long 命令完整的帮助信息
  • Args 命令的参数约束
  • Run 命令匹配成功后执行的函数体

很显然,我们这个命令工具暂时用不到子命令,所以我们直接使用一个根命令即可。

var rootCmd = &cobra.Command{
   Use: "app {word}", Short: "translate words",
		Long: `translate words to other language by cmdline`,
		Args: cobra.MinimumNArgs(1),
		Run: func(cmd *cobra.Command, args []string) {
   
			//do something
             fmt.Println("Arg:", strings.Join(args, " "))
			fmt.Println("translate:", "from", fromLan, "to", toLan)
		}}

根命令按照上面的定义即可。

还有两个flag需要添加到rootCmd上面,这两个选项是以kv键值对形式存在的,可以省略,所以需要提供一个默认值。根据有道智云的文档可以看到,翻译语言可以自动识别,所以我们只需要默认设置成auto即可

rootCmd.Flags().StringVarP(&fromLan, "from", "f", "auto", "translate from this language")
rootCmd.Flags().StringVarP(&toLan, "to", "t", "auto", "translate to this language")

此处我们需要定义两个字符串变量来接收这两个flag的值

var fromLan string
var toLan string

然后只需要将这个命令运行起来即可

rootCmd.Execute()

完整代码:

package main

import (
	"fmt"
	"strings"

	"github.com/spf13/cobra"
)

var fromLan string
var toLan string

func main() {
   
	var rootCmd = &cobra.Command{
   Use: "app {word}", Short: "translate words",
		Long: `translate words to other language by cmdline`,
		Args: cobra.MinimumNArgs(1),
		Run: func(cmd *cobra.Command, args []string) {
   
			fmt.Println("Arg:", strings.Join(args, " "))
			fmt.Println("translate:", "from", fromLan, "to", toLan)
		}}

	rootCmd.Flags().StringVarP(&fromLan, "from", "f", "auto", "translate from this language")
	rootCmd.Flags().StringVarP(&toLan, "to", "t", "auto", "translate to this language")
	rootCmd.Execute()
}
PS E:\code\code_go\Godict\test> go build
PS E:\code\code_go\Godict\test> ./test nice --from en --to zh-CSH
Arg: nice
translate: from en to zh-CSH

加载config.json配置

由于golang自带有json编解码库,所以我们使用json格式的配置文件。

如前面所述,配置文件需要加载appKey和appSecret两个参数,因此定义如下:

{
   
    "appKey":"your app key",
    "appSecret":"your app secret code"
}

json在golang中,使用tag来指定json与结构体的映射

type Config struct {
   
	AppKey    string `json:"appKey"`
	AppSecret string `json:"appSecret"`
}

json是一个文本文件,所以我们首先需要把文件中的内容读取出来

fileobj, err := os.Open(str)
if err != nil {
   
	return err
}

defer fileobj.Close()

var fileContext []byte
fileContext, err = ioutil.ReadAll(fileobj)

然后将读取出来的内容使用json.Unmarshal函数解析

json.Unmarshal(fileContext, cfg)

我们将此部分代码定义成一个函数方便调用:

func InitConfig(str string, cfg *Config) error {
   
	fileobj, err := os.Open(str)
	if err != nil {
   
		return err
	}

	defer fileobj.Close()

	var fileContext []byte
	fileContext, err = ioutil.ReadAll(fileobj)

	json.Unmarshal(fileContext, cfg)
	return nil
}

此处函数需要传入config.json文件的路径和解析成功后保存数据的Config变量指针。我们此处规定加载应用同级目录下的config.json。所以我们需要能获取应用程序的绝对路径,此处使用绝对路径是为了保证config.json一定能获取到。

绝对路径可以使用一下方式获取:

dir, err := filepath.Abs(filepath.Dir(os.Args[0]))

整理成一个函数方便调用:

func GetCurrentDirectory() string {
   
	dir, err := filepath.Abs(filepath.Dir(os.Args[0]))
	if err != nil {
   
		log.Fatal(err)
		return ""
	}
	return strings.Replace(dir, "\\", "/", -1) //将\替换成/
}

上述完整代码和测试:

package main

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"path/filepath"
	"strings"

	"github.com/spf13/cobra"
)

type Config struct {
   
	AppKey    string `json:"appKey"`
	AppSecret string `json:"appSecret"`
}

var config Config
var fromLan string
var toLan string

func main() {
   
	var rootCmd = &cobra.Command{
   Use: "app {word}", Short: "translate words",
		Long: `translate words to other language by cmdline`,
		Args: cobra.MinimumNArgs(1),
		Run: func(cmd *cobra.Command, args []string) {
   
			fmt.Println
  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值