一、简介
Golang诞生已经超过十个年头了,发展得愈发完善,其简单方便的协程并发机制使得其在爬虫领域有着一定的天赋。
首先我们来看一看,Golang相对于Python这个爬虫领域的传统强者,有哪些优点和缺点。
优点:
- 完善简便的协程并发机制
- 并发数量大
- 占用资源少
- 运行速度更快
- 部署方便
缺点:
- 数据处理比较繁琐
- 成熟工具不是很多
- 资料较少
- 实现相同逻辑需要的代码更多
由于Golang本身静态语言的特性,和其特别的异常处理方式等等原因,在发起较复杂的请求时需要的代码量自然会比Python多不少,但是其并发的数量也是远超Python的,所以两者应用的场景并不十分相同,我们可以根据需要灵活的选择。
在刚刚接触Golang的http包时,觉得其非常的方便,发起请求只需要一行代码:
http.Get("https://www.baidu.com")
就算与Python的requests
在便利方面也不遑多让,然而在Golang勾起了我的兴趣,并深入接触后,我发现并非如此。最简单的http.Get
方法只能发起最简单的请求,一旦要设置headers、cookies等属性时,需要写的代码会成几何倍数上升,而设置代理或者管理重定向等操作,会更加复杂。
这个摸索的过程中最痛苦的是,在网上能找到资料非常的稀少,大多数时候只能阅读官方文档和阅读net
标准库的源码。所幸Go语言的特性使得阅读Go源码是一件比较简单的事,相对于其他语言来说。
所以本篇文章的目的,是为了让那些使用Golang的朋友,对如何使用Golang发起请求有一个比较全面的了解。
注1:Golang中文官网的文档版本比较低,有些地方与最新版本不同,有条件的同学可以爬爬梯子,去golang.org英文官网看文档。
注2:文中代码为了简洁,省略掉了异常处理的部分,实际使用时需要按情况加上。
二、简单请求
Golang中的net
包封装了大部分网络相关的功能,我们基本不需要借助其他库就能实现我们的爬虫需求。其中最为常用的是http
和url
,使用前可以根据我们的需要进行导入:
import (
"net/http"
"net/url"
)
http
提供了一些非常方便的接口,可以实现最简单的请求,例如Get、Post、Head:
resp, err := http.Get("http://example.com/")
...
resp, err := http.Post("http://example.com/upload", "image/jpeg", &buf)
...
resp, err := http.PostForm("http://example.com/form",
url.Values{"key": {"Value"}, "id": {"123"}})
可以看到,我们非常简单的就发起了请求并获得了响应,这里需要注意一点的是,获得的响应body需要我们手动关闭:
resp, err := http.Get("http://example.com/")
if err != nil {
// 处理异常
}
defer resp.Body.Close() // 函数结束时关闭Body
body, err := ioutil.ReadAll(resp.Body) // 读取Body
// ...
这样的请求方式是非常方便的,但是当我们需要定制我们请求的其他参数时,就必须要使用其他组件了。
三、Client
Client
是http
包内部发起请求的组件,使用它,我们才可以去控制请求的超时、重定向和其他的设置。以下是Client的定义:
type Client struct {
Transport RoundTripper
CheckRedirect func(req *Request, via []*Request) error
Jar CookieJar
Timeout time.Duration // Go 1.3
}
首先是生成Client对象:
client := &http.Client{}
Client也有一些简便的请求方法,如:
resp, err := client.Get("http://example.com")
但这种方法与直接使用http.Get
没多大差别,我们需要使用另一个方法来定制请求的Header、请求体、证书验证等参数,这就是Request
和Do
。
3.1. 设置超时
这是一张说明Client超时的控制范围的图:
这其中,设置起