百度抓包练习
实践内容概述:
本实践基于go语言基础教程的课后作业。详细记录了通过编写HTTP请求来进行百度翻译英译汉的抓包。本笔记仅供个人参考。以最基础易懂的详细视角记录实现过程。
环境:
VS Code
Go1.17
操作系统:macOS Ventura 13.4
操作步骤
1.获得HTTP请求文件进行代码化
- 在百度翻译网页版,随便翻译一个英语单词(以word为例)
在这个过程中,本地向百度翻译的服务器发出POST请求,将待查单词、翻译类型和语言作为请求内容发出。在检查页面元素的街面上,“网络”一栏包括了该网页在网络上的交互操作,包括了一切静态资源在网页上的显示、与用户和与数据库的交互等。我们检索其文件列表形式,筛选 XHR/Fetch
这里牵扯到一个十分愚蠢的问题,导致我浪费了很多时间。
以下是包含HTTP请求文件,其中有我们需要的词汇翻译,也有其他的比如语言种类判断,音视频、广告等我们不需要的信息。
以下两个文件是词汇翻译:
- v2transapi (此文件是完整的释义,包括音频朗读和不同词典对单词的解释等等。)这个文件的内容较为复杂,嵌套的结构很多。
- sug (此文件仅仅包括对词义的翻译而没有其他解释。)内容、结构都很简单。
将一个请求代码化,我们需要将这个请求文件以Curl的形式转化为go语言。在这里我使用了 curl converter。
将响应代码化:我们需要的是响应中的数据,也就是对单词的翻译。我们可以直接从响应内容中的json格式的数据转化为golang struct 这个结构体便于我们在代码中读取。我使用了OKTools。
我最初试图将v2transapi代码化,但是总不能成功。原因如下:
这是v2transapi的标头中的请求数据。
请求数据 MIME类型: application/x-www-form-urlencoded; charset=UTF-8 from: en to: zh query: word transtype: translang simple_means_flag: 3 sign: 924944.720417 token: dc82182c395b4e26b05c50d65e39f165 domain: common ts: 1691726336728
这些请求数据是我们在发送POST请求时需要提供的,在代码中用一个结构体来表示。
我们需要单次有效的token以及时间戳。但问题是这部分需要通过百度的服务器生成。而我的目标是,请求数据仅通过用户输入便可以达到。
因此我最后选择将sug文件代码化,因为它对请求数据的要求只有提供待查询单词。
请求数据 MIME类型: application/x-www-form-urlencoded; charset=UTF-8 kw: word
此处 kw (keyword)是我们唯一需要输入的,待查单词。
因此可以使用这个文件进行抓包。
2. 编写查询函数
func Bquery(word string) {
client := &http.Client{}
request := BDictRequest{BKeyWord: word}
buf, err := json.Marshal(request)
if err != nil {
log.Fatal(err)
}
var data = bytes.NewReader(buf)
//var data = strings.NewReader(`kw=`)
req, err := http.NewRequest("POST", "https://fanyi.baidu.com/sug", data)
if err != nil {
log.Fatal(err)
}
req.Header.Set("Content-Type", "application/json;charset=UTF-8")
//req.Header.Set("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8")
req.Header.Set("Accept", "application/json, text/javascript,*/*; q=0.01")
req.Header.Set("Sec-Fetch-Site", "same-origin")
req.Header.Set("Accept-Language", "zh-CN,zh-Hans;q=0.9")
// req.Header.Set("Accept-Encoding", "gzip, deflate, br")
req.Header.Set("Sec-Fetch-Mode", "cors")
req.Header.Set("Host", "fanyi.baidu.com")
req.Header.Set("Origin", "https://fanyi.baidu.com")
req.Header.Set("Content-Length", "8")
req.Header.Set("User-Agent", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.5 Safari/605.1.15")
req.Header.Set("Referer", "https://fanyi.baidu.com/")
req.Header.Set("Connection", "keep-alive")
req.Header.Set("Sec-Fetch-Dest", "empty")
req.Header.Set("X-Requested-With", "XMLHttpRequest")
resp, err := client.Do(req)
if err != nil {
log.Fatal(err)
}
defer resp.Body.Close()
bodyText, err := io.ReadAll(resp.Body)
if err != nil {
log.Fatal(err)
}
var dictResponse BDictResponse
err = json.Unmarshal(bodyText, &dictResponse)
if err != nil {
log.Fatal(err)
}
//fmt.Printf("%s\n", bodyText)
fmt.Println("以下是百度翻译的结果")
fmt.Println(word, "单词:", dictResponse.Data[0], "名称:", dictResponse.Data[1])
}
此函数其实只需要在由sug文件转化的代码上稍作修改:
- 将请求中的keyword改为由用户输入的变量
- 打印结果
3. 整理报文结构
我们的目的是将百度响应的报文打印为json格式,并且转化为汉字。(如果直接打印响应体,就会发现是unicode)。可以使用json.Unmarshall()进行转化。
此外
以下是请求数据的关键词和响应报文的结构。
type BDictRequest struct {
BKeyWord string `json:"kw"`
}
type BDictResponse struct {
Errno int `json:"errno"`
Data []struct {
K string `json:"k"`
V string `json:"v"`
} `json:"data"`
}
4. 两个翻译引擎并发请求
在课上抓包的例子使用了彩云小译。在这里我们并行请求,同时对百度翻译和彩云小译进行抓包,以此提高响应速度。
go语言的特点之一就是高并发。goroutine是比线程更小的单位,通过命令 go 开启。 我们让用户输入待查单词后,创建百度翻译的gorourine,这样让其与彩云小译同时执行。如果百度翻译的响应速度更快,最终两种翻译引擎的结果都会被打印出来。如果彩云小译的响应速度更快,那么在彩云小译得到结果之后,百度翻译的被迫中止,最后只打印出彩云小译的结果。 以下是两个搜索引擎的结果在终端的打印:
(base) river@rivers-MacBook-Pro fetch % cd /Users/river/go/src/go/fetch ; /usr/bin/env GOPATH=/Users/river/go /Users/river/go/bin/dlv dap --check-go-version=false --client-addr=: 56851 inter your word apple 以下是百度翻译的结果 apple 单词: {Apple n. 苹果公司,原称苹果电脑公司} 名称: {apple n. 苹果; 苹果公司; 苹果树} 以下是彩云小译的结果 apple UK: [ˈæpl] US: [ˈæpl] n.苹果;苹果树 [俗]形似苹果之物;掌上明珠,心肝宝贝