这是我参与「第五届青训营」笔记创作活动的第4天!
案例二 在线词典——抓包
案例题目
功能:实现在命令行输入一个单词,输出该单词相关的音标和翻译
原理:调用第三方的API对单词进行翻译并打印出来
思路分析
1. 抓包
以彩云小译为例,进行抓包操作 在翻译时检查页面,触发了Post请求
对dict中的负载进行分析,有要翻译的单词good,en2zh说明是英文翻译到中文
dict中的预览则包含了更多关于good的音标和翻译
2. 代码生成
通过复制dict的cURL得到该curl命令 在终端中打开如下:
打开curlconverter.com/#go 将刚才得到的curl命令粘贴到其中,选择Go并生成代码
对该生成代码进行分析
package main
import (
"fmt"
"io/ioutil"
"log"
"net/http"
"strings"
)
func main() {
client := &http.Client{}
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", "")
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="109", "Chromium";v="109"`)
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/109.0.0.0 Safari/537.36 Edg/109.0.1518.61")
req.Header.Set("x-authorization", "token:qgemv4jr1y38jyq6vhvi")
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)
}
fmt.Printf("%s\n", bodyText)
}
运行后生成相应的JSON
3. 生成request body
定义DictRequest结构体
type DictRequest struct {
TransType string `json:"trans_type"`
Source string `json:"source"`
UserID string `json:"user_id"`
}
代码部分修改
client := &http.Client{}
request := DictRequest{TransType: "en2zh", Source: "good"} //初始化结构体变量
buf, err := json.Marshal(request) //将request序列化成数组
if err != nil {
log.Fatal(err)
}
var data = bytes.NewReader(buf) //修改返回类型为byte数组,非字符串形式
req, err := http.NewRequest("POST", "https://api.interpreter.caiyunai.com/v1/dict", data)
if err != nil {
log.Fatal(err)
}
4. 解析response body
对preview中的JSON进行结构体生成
对源代码部分进行修改
var dictResponse DictResponse
err = json.Unmarshal(bodyText, &dictResponse) //反序列化
if err != nil {
log.Fatal(err)
}
fmt.Printf("%#v\n", dictResponse)
5. 打印结果和代码修改
对原打印代码dictResponse进行修改获得想要的翻译信息
fmt.Println(word, "UK:", dictResponse.Dictionary.Prons.En, "US:", dictResponse.Dictionary.Prons.EnUs)
for _, item := range dictResponse.Dictionary.Explanations {
fmt.Println(item)
添加一个序列码的检验,以防止出现空结果时纠错
if resp.StatusCode != 200 {
log.Fatal("bad StatusCode:", resp.StatusCode, "body", string(bodyText))
}
6.代码完善
func main() {
//错误处理,若判断os.Args不是两个则打印错误信息
if len(os.Args) != 2 {
fmt.Fprintf(os.Stderr, `usage: simpleDict WORD
example: simpleDict hello
`)
os.Exit(1)
}
//若正确则调用query即可
word := os.Args[1]
query(word)
}
执行效果如下
总结
这次的项目是用Go语言实现抓包,整体来说比较复杂。不仅需要对前端网页的布局有一定认识,也要对后端整体的结构体和代码进行新的布局和修改。同时也运用了一些外部网站对curl命令进行代码生成,对JSON进行结构体生成等。在对代码进行修改时,应注意适当的添加一些错误处理检验部分,优化代码的完整性。