Go语言colly框架的快速入门

 更新时间:2023年07月26日 10:38:34   作者:凉凉的知识库  
Python 中非常知名的爬虫框架有Scrapy,Go 中也有一些 star 数较高的爬虫框架,colly就是其中的佼佼者,它 API 简洁,性能优良,开箱即用,今天就来快速学习一下吧

有些人可能认为爬虫框架和 http client 库的功能一样,用 http client 库也可以写爬虫。当然,无论用第三方的 http client 库还是官方的http库,都可以写爬虫。但术业有专攻,爬虫框架专门为批量爬取设计,往往拥有并发控制、队列、缓存、HTML 解析等一系列开箱即用的 API,能大幅简化在爬虫实现过程中的负担

Python 中非常知名的爬虫框架有Scrapy,Go 中也有一些 star 数较高的爬虫框架。colly就是其中的佼佼者,它 API 简洁,性能优良,开箱即用。今天就来快速学习一下吧!

基本使用

首先引入依赖

go get -u github.com/gocolly/colly/...

之后就可以使用colly,通过Visit函数来告知colly 采集器要访问的 URL

package main
import (
	"fmt"
	"github.com/gocolly/colly/v2"
)
func main() {
	c := colly.NewCollector()
	c.Visit("http://go-colly.org/")
}

这样就行了么?运行下试试,没有任何输出。

$ go run main.go

原因在于代码要求 colly 采集器访问http://go-colly.org/,但没有设定访问 URL 成功或者失败后要执行的动作。colly提供了一系列的回调函数,用于 URL 访问和响应过程中各种情况的处理

例如,可以设定访问 URL 前、响应成功、响应失败时不同逻辑的处理

package main
import (
	"fmt"
	"github.com/gocolly/colly/v2"
)
func main() {
	c := colly.NewCollector()
	c.OnRequest(func(r *colly.Request) {
		fmt.Println("Visiting", r.URL)
	})
	c.OnResponse(func(r *colly.Response) {
		fmt.Println("Visited", r.Request.URL)
	})
	c.OnError(func(_ *colly.Response, err error) {
		fmt.Println("Something went wrong:", err)
	})
	c.Visit("http://go-colly.org/")
}

colly提供的回调和回调的顺序如下图,每个回调可以设置多次,会依次执行

常规配置

配置分两部分,一部分是 colly 采集器的配置,一部分是 HTTP 的配置

colly 采集器的配置

新建 colly 采集器时指定配置,例如

c := colly.NewCollector(
	colly.UserAgent("example.com"),
	colly.DisallowedDomains("baidu.com", "bing.com"),
)
//...
c.Visit("http://baidu.com/")
c.Visit("http://go-colly.org/")

使用环境变量可以不用重新编译代码。看名字大家应该也能猜到每个环境变量都有什么作用

注意环境变量有固定前缀COLLY_,官方文档里并没有说明(坑!)

  • COLLY_ALLOWED_DOMAINS (逗号分隔)
  • COLLY_CACHE_DIR (string)
  • COLLY_DETECT_CHARSET (y/n)
  • COLLY_DISABLE_COOKIES (y/n)
  • COLLY_DISALLOWED_DOMAINS (逗号分隔)
  • COLLY_IGNORE_ROBOTSTXT (y/n)
  • COLLY_MAX_BODY_SIZE (int)
  • COLLY_MAX_DEPTH (0 代表不限深度)
  • COLLY_PARSE_HTTP_ERROR_RESPONSE (y/n)
  • COLLY_USER_AGENT (string)

$ COLLY_DISALLOWED_DOMAINS=baidu.com,bing.com go run main.go
Visiting http://go-colly.org/
Visited http://go-colly.org/
Finished http://go-colly.org/

通过 colly 采集器的属性进行配置

c := colly.NewCollector()
c.UserAgent = "example.com"
//...
c.Visit("http://go-colly.org/")
c.DisallowedDomains = []string{"baidu.com", "bing.com"}
c.Visit("http://baidu.com/")

colly 采集器的配置优先级就是上面介绍的顺序:新建 < 环境变量 < 实例属性

HTTP 的配置

colly 默认使用的是 Go 标准库中的 http client,我们可以进行替换

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,
}

常见功能

作为一个爬虫,很少会仅抓取一个链接,通常会抓取大量的链接,甚至会不断分析当前页面中的链接,继续进行深度的爬取。代码通常会类似下面

为了避免无限制的爬取,可以限制爬取的域名范围,和访问深度;

colly 会记录已经爬取过的链接,不会再重复爬取

func main() {
	c := colly.NewCollector(
		colly.AllowedDomains("httpbin.org"),
		colly.MaxDepth(2),
	)
	c.OnHTML("a[href]", func(e *colly.HTMLElement) {
		link := e.Attr("href")
		fmt.Printf("Link found: %q -> %s\n", e.Text, link)
		c.Visit(link)
	})
	c.OnError(func(_ *colly.Response, err error) {
		fmt.Println("Something went wrong:", err)
	})
	c.Visit("http://httpbin.org/links/20/3")
}

并行抓取

colly 默认是串行逐个链接进行爬取,想要提高爬取能力最快速简单的方式就是开启并行。

除了需要设置colly.Async(true)之外,还需要在最后c.Wait()等待所有并发的请求执行完成

c.Limit可以针对某一个域名设置并发度和发起每一个请求的延迟时间

func main() {
	c := colly.NewCollector(
		colly.AllowedDomains("httpbin.org"),
		colly.MaxDepth(2),
		colly.Async(true),
	)
	c.OnHTML("a[href]", func(e *colly.HTMLElement) {
		link := e.Attr("href")
		fmt.Printf("Link found: %q -> %s\n", e.Text, link)
		c.Visit(link)
	})
  c.Limit(&colly.LimitRule{
		DomainGlob:  "*httpbin.*",
		Parallelism: 2,
		Delay:      5 * time.Second,
	})
	c.Visit("http://httpbin.org/links/20/3")
	c.Wait()
}

持久化的外部存储

默认情况下已访问的 URL 和 cookie 等信息都是存储在内存中,服务重新启动后将会丢失这部分信息,且无法在多个机器直接共享。

当我们构建一个分布式爬虫时,我们需要一个公共的用于维护状态的持久化存储,例如 redis 等。

package main
import (
	"fmt"
	"github.com/gocolly/colly/v2"
	"github.com/gocolly/redisstorage"
)
func main() {
	c := colly.NewCollector(
		colly.AllowedDomains("httpbin.org", "go-colly.org"),
		colly.MaxDepth(2),
	)
	storage := &redisstorage.Storage{
		Address:  "127.0.0.1:6379",
		Password: "",
		DB:       0,
		Prefix:   "httpbin_test",
	}
	err := c.SetStorage(storage)
	if err != nil {
		panic(err)
	}
  // 清除之前存储的信息,可选
	if err := storage.Clear(); err != nil {
		panic(err)
	}
	defer storage.Client.Close()
	c.OnHTML("a[href]", func(e *colly.HTMLElement) {
		link := e.Attr("href")
		fmt.Printf("Link found: %q -> %s\n", e.Text, link)
		c.Visit(link)
	})
  // ...
	c.Visit("http://httpbin.org/links/20/3")
}

队列

可以使用队列来控制爬取的速率,默认情况下队列也是在内存中的

import (
	"fmt"
	"github.com/gocolly/colly/v2"
	"github.com/gocolly/colly/v2/queue"
)
func main() {
	q, _ := queue.New(
		2, // 消费的进程数
		&queue.InMemoryQueueStorage{MaxSize: 10000}, // 默认的队列,内存队列
	)
	c := colly.NewCollector(
		colly.AllowedDomains("httpbin.org", "go-colly.org"),
		colly.MaxDepth(2),
	)
	c.OnHTML("a[href]", func(e *colly.HTMLElement) {
		link := e.Attr("href")
		fmt.Printf("Link found: %q -> %s\n", e.Text, link)
		q.AddURL(link)
	})
	q.AddURL("http://go-colly.org/")
	q.Run(c)
}

对于构建分布式爬虫来说,可以借助外部的队列提高整体的消费能力。

package main
import (
	"fmt"
	"github.com/gocolly/colly/v2"
	"github.com/gocolly/colly/v2/queue"
	"github.com/gocolly/redisstorage"
)
func main() {
	// 创建redis存储
	storage := &redisstorage.Storage{
		Address:  "127.0.0.1:6379",
		Password: "",
		DB:       0,
		Prefix:   "httpbin_test",
	}
	q, err := queue.New(
		2, // 消费的进程数
		storage,
	)
	if err != nil{
		panic(err)
	}
	c := colly.NewCollector(
		colly.AllowedDomains("httpbin.org", "go-colly.org"),
		colly.MaxDepth(2),
	)
  err = c.SetStorage(storage)
	if err != nil {
		panic(err)
	}
	c.OnHTML("a[href]", func(e *colly.HTMLElement) {
		link := e.Attr("href")
		fmt.Printf("Link found: %q -> %s\n", e.Text, link)
		q.AddURL(link)
	})
	q.AddURL("http://go-colly.org/")
	q.Run(c)
}

总结

这篇文章作为一个入门介绍,看完后你应该能 Get 到普通的 http client 库和爬虫库的区别了吧。

colly 作为一个爬虫框架集成了一系列针对爬虫的 API,想要体验 colly 的更多能力,建议还是好好阅读下 colly 的文档

到此这篇关于Go语言colly框架的快速入门的文章就介绍到这了,更多相关Go colly框架内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • golang使用DockerFile正确用法指南

    golang使用DockerFile正确用法指南

    docker在开发和运维中使用的场景越来越多,作为开发人员非常有必要了解一些docker的基本知识,而离我们工作中最近的也就是对应用的docker部署编排了,这篇文章主要给大家介绍了关于golang使用DockerFile的正确用法指南,需要的朋友可以参考下
    2024-03-03
  • Golang利用casbin实现权限验证详解

    Golang利用casbin实现权限验证详解

    Casbin是一个强大的、高效的开源访问控制框架,其权限管理机制支持多种访问控制模型,Casbin只负责访问控制。本文将利用casbin实现权限验证功能,需要的可以参考一下
    2023-02-02
  • 基于Golang container/list实现LRU缓存

    基于Golang container/list实现LRU缓存

    Least Recently Used (LRU) ,即逐出最早使用的缓存,这篇文章主要为大家介绍了如何基于Golang container/list实现LRU缓存,感兴趣的可以了解下
    2023-08-08
  • golang判断结构体为空的问题

    golang判断结构体为空的问题

    这篇文章主要介绍了golang判断结构体为空的问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-02-02
  • GO语言利用K近邻算法实现小说鉴黄

    GO语言利用K近邻算法实现小说鉴黄

    本文给大家分享的是一段GO语言利用K近邻算法实现小说鉴黄的方法,本方法的鉴别的关键是关键是向量点的选择和阈值的判定,推荐给大家,有需要的小伙伴可以参考下。
    2015-03-03
  • 一文带你深入理解Golang中的泛型

    一文带你深入理解Golang中的泛型

    Go 在泛型方面一直被诟病,因为它在这方面相对比较落后。但是,在 Go 1.18 版本中,泛型已经被正式引入,成为了 Go 语言中一个重要的特性。本文将会详细介绍 Go 泛型的相关概念,语法和用法,希望能够帮助大家更好地理解和应用这一特性
    2023-05-05
  • Golang程序漏洞检测器govulncheck的安装和使用

    Golang程序漏洞检测器govulncheck的安装和使用

    govulncheck 是一个命令行工具,可以帮助 Golang 开发者快速找到项目代码和依赖的模块中的安全漏洞,该工具可以分析源代码和二进制文件,识别代码中对这些漏洞的任何直接或间接调用,本文就给大家介绍一下govulncheck安装和使用,需要的朋友可以参考下
    2023-09-09
  • Go语言基础之网络编程全面教程示例

    Go语言基础之网络编程全面教程示例

    这篇文章主要为大家介绍了Go语言基础之网络编程全面教程示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-12-12
  • Go语言中for和range的性能比较

    Go语言中for和range的性能比较

    这篇文章主要为大家详细介绍了Go语言中for和range语句的使用以及性能比较,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起了解一下
    2023-07-07
  • golang与非golang程序探测beyla源码解读

    golang与非golang程序探测beyla源码解读

    这篇文章主要为大家介绍了beyla源码解读之golang与非golang程序的探测实例,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-12-12

最新评论