《Go语言四十二章经》第四十一章 网络爬虫

作者:李骁

41.1 go-colly

go-colly是用Go实现的网络爬虫框架。go-colly快速优雅,在单核上每秒可以发起1K以上请求;以回调函数的形式提供了一组接口,可以实现任意类型的爬虫。

Colly 特性:

清晰的API
快速(单个内核上的请求数大于1k)
管理每个域的请求延迟和最大并发数
自动cookie 和会话处理
同步/异步/并行抓取
高速缓存
自动处理非Unicode的编码
Robots.txt 支持

下面是官方提供的抓取例子:

  1. package main
  2. import (
  3. "fmt"
  4. "github.com/gocolly/colly"
  5. )
  6. func main() {
  7. c := colly.NewCollector()
  8. // Find and visit all links
  9. c.OnHTML("a[href]", func(e *colly.HTMLElement) {
  10. e.Request.Visit(e.Attr("href"))
  11. })
  12. c.OnRequest(func(r *colly.Request) {
  13. fmt.Println("Visiting", r.URL)
  14. })
  15. c.Visit("http://go-colly.org/")
  16. }

程序输出:

  1. Visiting http://go-colly.org/
  2. Visiting http://go-colly.org/docs/
  3. Visiting http://go-colly.org/articles/
  4. Visiting http://go-colly.org/services/
  5. Visiting http://go-colly.org/datasets/
  6. ......

Colly大致的使用说明:

在代码中导入包:

  1. import "github.com/gocolly/colly"

colly的主体是Collector对象,管理网络通信和负责在作业运行时执行附加的回掉函数。使用colly需要先初始化Collector:

  1. c := colly.NewCollector()

可以向colly附加各种不同类型的回调函数,来控制收集作业或获取信息:
回调函数的调用顺序如下:

  1. OnRequest
    在发起请求前被调用

  2. OnError
    请求过程中如果发生错误被调用

  3. OnResponse
    收到回复后被调用

  4. OnHTML
    在OnResponse之后被调用,如果收到的内容是HTML

  5. OnScraped
    在OnHTML之后被调用

41.2 goquery
colly框架配合goquery库,功能更加强大。goquery将jQuery的语法和特性引入到了Go语言中,可以更灵活地选择采集内容的数据项。

  1. package main
  2. import (
  3. "bytes"
  4. "fmt"
  5. "log"
  6. "net/url"
  7. "time"
  8. "github.com/PuerkitoBio/goquery"
  9. "github.com/gocolly/colly"
  10. )
  11. func main() {
  12. urlstr := "http://metalsucks.net"
  13. u, err := url.Parse(urlstr)
  14. if err != nil {
  15. log.Fatal(err)
  16. }
  17. c := colly.NewCollector()
  18. c.SetRequestTimeout(100 * time.Second)
  19. // 指定Agent信息
  20. c.UserAgent = "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.108 Safari/537.36"
  21. c.OnRequest(func(r *colly.Request) {
  22. r.Headers.Set("Host", u.Host)
  23. r.Headers.Set("Connection", "keep-alive")
  24. r.Headers.Set("Accept", "*/*")
  25. r.Headers.Set("Origin", u.Host)
  26. r.Headers.Set("Referer", urlstr)
  27. r.Headers.Set("Accept-Encoding", "gzip, deflate")
  28. r.Headers.Set("Accept-Language", "zh-CN, zh;q=0.9")
  29. })
  30. c.OnResponse(func(resp *colly.Response) {
  31. // 读取url内容 colly读取的内容传入给goquery
  32. htmlDoc, err := goquery.NewDocumentFromReader(bytes.NewReader(resp.Body))
  33. if err != nil {
  34. log.Fatal(err)
  35. }
  36. // 找到抓取项
  37. htmlDoc.Find(".sidebar-reviews article .content-block").Each(func(i int, s *goquery.Selection) {
  38. band := s.Find("a").Text()
  39. title := s.Find("i").Text()
  40. fmt.Printf("Review %d: %s - %s\n", i, band, title)
  41. })
  42. })
  43. c.OnError(func(resp *colly.Response, errHttp error) {
  44. err = errHttp
  45. })
  46. err = c.Visit(urlstr)
  47. }

程序输出:

  1. Review 0: Obscura - Diluvium
  2. Review 1: Skeletonwitch - Devouring Radiant Light
  3. Review 2: Deafheaven - Ordinary Corrupt Human Love
  4. Review 3: Between the Buried and Me - Automata II
  5. Review 4: Chelsea Grin - Eternal Nightmare

Colly + goquery 是抓取网络内容的利器,使用上极其方便。如今动态渲染的页面越来越多,爬虫们或多或少都需要用到headless browser来渲染待爬取的页面,这里推荐chromedp,开源网址:https://github.com/chromedp/chromedp