Golang学习之POST请求

我终于失去了你,在拥挤的人群中。

最近在用 Python 写爬虫, 然后就想用 Go 写一写, 然后稀里糊涂的发现这个站有一个接口可以直接请求数据, 那还爬啥啊, 请求吧。

然后发现不会写 POST 接口, 简直菜的抠脚。

其实也没啥, 就是有一个坑, 请求头必须要设定Content-Type为application/x-www-form-urlencoded,post参数才可正常传递。然后就没啥了。

所有代码仅作为学习啊。

贴代码吧

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
package main

import (
"fmt"
"io/ioutil"
"log"
"net/http"
"net/url"
"strconv"
"strings"
"time"
)

func fetch(targetURL string, i int, ch chan bool) {
fmt.Println("[+] Fetch URL", targetURL)

data := url.Values{
"codeId": {""},
"page": {strconv.Itoa(i)},
"size": {"100"},
"fileType": {""},
"channelWebPath": {""},
"channelLevels": {""}}
body := strings.NewReader(data.Encode())

req, _ := http.NewRequest("POST", targetURL, body)

req.Header.Set("User-Agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)")
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")

client := &http.Client{}
resp, err := client.Do(req)

if err != nil {
log.Fatal("Http get err:", err)
}

if resp.StatusCode != 200 {
log.Fatal("Http status code:", resp.StatusCode)
}

defer resp.Body.Close()

respBody, _ := ioutil.ReadAll(resp.Body)
fmt.Println(string(respBody))

ch <- true

}

func main() {
start := time.Now()
url := ""
ch := make(chan bool)

for i := 1; i < 100; i++ {
go fetch(url, i, ch)
}

for i := 1; i < 100; i++ {
<-ch
}

elapsed := time.Since(start)
fmt.Printf("Took %s", elapsed)
}

请求头必须要设定Content-Type为application/x-www-form-urlencoded,post参数才可正常传递。

goroutine的用法

这里有一个关于 goroutine 的用法问题。

这个东西是啥就不BB了。

有没有像Python多进程/线程的那种等待子进/线程执行完的join方法呢?当然是有的,可以让 Go 协程之间信道(channel)进行通信:从一端发送数据,另一端接收数据,信道需要发送和接收配对,否则会被阻塞:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
func fetch(targetURL string, i int, ch chan bool) {
...
ch <- true
}

func main() {
start := time.Now()
url := ""
ch := make(chan bool)

for i := 1; i < 100; i++ {
go fetch(url, i, ch)
}

for i := 1; i < 100; i++ {
<-ch
}

elapsed := time.Since(start)
fmt.Printf("Took %s", elapsed)
}

而在main函数中,在用一个for循环,<- ch 会等待接收数据(这里只是接收,相当于确认任务完成)。