go-colly:快速、优雅的 Go 语言爬虫框架
Colly 提供了一个干净的接口来编写任何类型的爬虫、采集器、蜘蛛
使用 Colly,可以快速从网站中提取结构化数据,这些数据可用于广泛的应用程序,如数据挖掘、数据处理或归档。
特性
- 干净的API
- 快速 (单核 >1k 请/秒)
- 管理请求延迟和每个域名的最大并发性
- 自动cookie和会话处理
- 同步/异步/并行抓取
- 分布式爬取
- 缓存
- 非unicode响应的自动编码
- Robots.txt 支持
- Google App Engine 支持
安装
在终端输入如下命令安装 Colly:
go get -u github.com/gocolly/colly/...
开始
首先, 引入 Colly:
import "github.com/gocolly/colly"
Collector
Colly 主要的实体是 Collecotr
对象。Collector
管理网络通信,并负责在 collector 作业运行时执行附加的回调。要使用colly,您必须初始化 Collector
:
c := colly.NewCollector()
回调
您可以将不同类型的回调函数附加到 Collector
,用以控制收集作业或检索信息。查看软件包文档中的相关部分。
将回调添加到 Collector
c.OnRequest(func(r *colly.Request) {
fmt.Println("Visiting", r.URL)
})
c.OnError(func(_ *colly.Response, err error) {
log.Println("Something went wrong:", err)
})
c.OnResponse(func(r *colly.Response) {
fmt.Println("Visited", r.Request.URL)
})
c.OnHTML("a[href]", func(e *colly.HTMLElement) {
e.Request.Visit(e.Attr("href"))
})
c.OnHTML("tr td:nth-of-type(1)", func(e *colly.HTMLElement) {
fmt.Println("First column of a table row:", e.Text)
})
c.OnXML("//h1", func(e *colly.XMLElement) {
fmt.Println(e.Text)
})
c.OnScraped(func(r *colly.Response) {
fmt.Println("Finished", r.Request.URL)
})
回调的调用顺序
1. OnRequest
请求前调用
2. OnError
在请求区间出错时调用
3. OnResponse
收到响应后调用
4. OnHTML
如果收到的内容是 HTML,则在 OnResponse
后调用
5. OnXML
如果收到的内容是 HTML 或 XML,则在 OnHTML
后调用
6. OnScraped
OnXML
回调后调用
配置
Colly 是可高度自定义的爬虫框架。它有合理的默认值,并提供了大量的更改选项。
Collector 配置
Collector
属性的完整列表可以在此处找到。初始化 collector
的推荐方法是使用 colly.NewCollector(options…)
使用默认设置创建 collector:
c1 := colly.NewCollector()
创建另外一个 collector 并修改 User-Agent 及 url revisit 选项:
c2 := colly.NewCollector(
colly.UserAgent("xy"),
colly.AllowURLRevisit(),
)
或者
c2 := colly.NewCollector()
c2.UserAgent = "xy"
c2.AllowURLRevisit = true
通过重写 Collector 的属性,可以在爬虫作业的任何点更改配置。
以下一个很好的例子是用 User-Agent 切换器,它在每次请求时都会更改 User-Agent:
const letterBytes = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
func RandomString() string {
b := make([]byte, rand.Intn(10)+10)
for i := range b {
b[i] = letterBytes[rand.Intn(len(letterBytes))]
}
return string(b)
}
c := colly.NewCollector()
c.OnRequest(func(r *colly.Request) {
r.Headers.Set("User-Agent", RandomString())
})
通过环境变量配置
Collector
默认配置可以通过环境变量进行更改。这使我们可以在不重新编译的情况下对 collector 进行微调。环境解析是 collector 初始化的最后一步,因此初始化后的每一次配置更改都会覆盖从环境中解析的配置。
环境配置变量
ALLOWED_DOMAINS
(域名列表,逗号隔开)CACHE_DIR
(string)DETECT_CHARSET
(y/n)DISABLE_COOKIES
(y/n)DISALLOWED_DOMAINS
(域名列表,逗号隔开)IGNORE_ROBOTSTXT
(y/n)MAX_BODY_SIZE
(int)MAX_DEPTH
(int - 0 为无限)PARSE_HTTP_ERROR_RESPONSE
(y/n)USER_AGENT
(string)
HTTP 配置
Colly 使用 Golang 的默认 http 客户端 作为网络层。HTTP 选项可以通过修改默认的 HTTP roundtripper 微调。
c := colly.NewCollector()
c.WithTransport(&http.Transport{
Proxy: http.ProxyFromEnvironment,
DialContext: (&net.Dialer{
Timeout: 30 * time.Second,
KeepAlive: 30 * time.Second,
DualStack: true,
}).DialContext,
MaxIdleConns: 100,
IdleConnTimeout: 90 * time.Second,
TLSHandshakeTimeout: 10 * time.Second,
ExpectContinueTimeout: 1 * time.Second,
}
内容解析
内容抓取到了,如何解析并获取咱们想要的内容呢?
以 html 为例(colly 也有 xml 等内容解析):
// refentry 内容
c.OnHTML(".refentry", func(element *colly.HTMLElement) {
// ...
})
OnHtml 第一个参数是 jquery风格的选择器,第二个参数是 callback,callback 会传入 HTMLElement 对象。HTMLElement 结构体:
type HTMLElement struct {
// 标签的名称
Name string
Text string
attributes []html.Attribute
// 当前的 request
Request *Request
// 当前的 response
Response *Response
// 当前节点的 DOM 元素
DOM *goquery.Selection
// 在该 callback 回调中,此 element 的索引
Index int
}
其中,能够经过 DOM 字段操做(增删节点)、遍历、获取节点内容。
DOM 字段是 Selection 类型,该类型提供了大量的方法。若是你用过 jQuery,你必定会以为熟悉。
举个例子,咱们想要删除 h1.refname 标签,并返回父元素的 html 内容:
c.OnHTML(".refentry", func(element *colly.HTMLElement) {
titleDom := element.DOM.Find("h1.refname")
title := titleDom.Text()
titleDom.Remove()
content, _ := element.DOM.Html()
// ...
})