go-colly 官方文档翻译

简介(Introduction)

  • 如何安装?
如何安装
  1. Colly 只依赖于Go 语言,你可以通过 安装指南 安装它
  2. 安装Colly,在终端输入如下命令然后回车安装Colly
go get -u github.com/gocolly/colly/...
  • 入门
入门
  1. 开始使用Colly之前确保你已经安装最新版本,更详细内容见安装指南
  2. 让我们从一些简单的例子开始
  3. 首先你需要导入Colly到你的代码中
import "github.com/gocolly/colly"
收集器

Colly 的主要实例是收集器对象,当Colly 收集器任务运行时,收集器负责网络通讯和执行附加的回调任务。你必须初始化收集器

c := colly.NewCollector()
回调

你可以把不同类型的回调函数附加到收集器上来控制收集任务,然后取回信息,你可以在包文档中查看相关章节

添加回调到收集器中
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
    OnResponse 正确执行后,如果接收到的文本是HTML时执行
  5. OnXML
    OnResponse 正确执行后,如果接收到的文本是XML时执行
  6. OnScraped
    OnXML 回调后调用
  • 配置
配置

Colly 是一个高度自定义的爬虫框架,它提供合理的默认配置,而且提供了大量的配置去改变它

收集器配置

全面的收集器属性列表可以在这儿查看,推荐使用colly.NewCollector(options...)这种方法来初始化收集器
使用默认配置创建一个收集器

c1 := colly.NewCollector()

创建另外一个收集器,改变User-Agent 和 Url Revisit

c2 := colly.NewCollector(
    colly.UserAgent("xy"),
    colly.AllowURLRevisit(),
)

或者

c2 := colly.NewCollector()
c2.UserAgent = "xy"
c2.AllowURLRevisit = true

通过重新设置收集器的属性可以在收集任务运行任何节点改变配置。
一个很好的例子是 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())
})

通过环境变量配置
收集器的默认配置可以通过环境变量来改变,它允许我们在不通过编译的情况下对配置进行微调
环境变量解析是在收集器初始化的最后一步执行,所以每个变量在初始化后的改变都可能被环境变量配置覆盖。
环境变量配置

  • 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 client 作为网络层,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,
}

最佳实践(Best Practices)

  • 调试
调试

有时候将log.Println()函数放到回调函数中就足够了,但有时候却不行。Colly有收集器调试的内置功能,调试器接口可以使用不同的调试器实现。

将调试器添加到收集器

从Colly的repo中添加基本的日志调试器debug

import (
    "github.com/gocolly/colly"
    "github.com/gocolly/colly/debug"
)

func main() {
    c := colly.NewCollector(colly.Debugger(&debug.LogDebugger{}))
    // [..]
}
实现一个自定义的调试器

你通过实现debug.Debugger类可以创建任何种类的调试器。一个好的例子是 LogDebugger

  • 分布式抓取

分布式爬虫可以被不同方式实现,取决于你的抓取任务是什么。大多数情况下,它足以扩展网络通信层,这可以使用代理和Colly的代理切换器轻松实现。

代理选择器

使用代理切换器仍然保持集中,而HTTP请求分布在多个代理之间。
Colly通过其SetProxyFunc()函数来切换代理。任意自定义的函数可以通过SetProxyFunc()传参,只要这个函数签名为func(*http.Request) (*url.URL, error)

注意
通过使用 -D 可以将ssh 服务用到 sockets5代理上

Colly 有一个内置的代理切换器,可以在每个请求上轮流切换代理列表
用法

package main

import (
    "github.com/gocolly/colly"
    "github.com/gocolly/colly/proxy"
)

func main() {
    c := colly.NewCollector()

    if p, err := proxy.RoundRobinProxySwitcher(
        "socks5://127.0.0.1:1337",
        "socks5://127.0.0.1:1338",
        "http://127.0.0.1:8080",
    ); err == nil {
        c.SetProxyFunc(p)
    }
    // ...
}

实现自定义的代理切换器:

var proxies []*url.URL = []*url.URL{
    &url.URL{Host: "127.0.0.1:8080"},
    &url.URL{Host: "127.0.0.1:8081"},
}

func randomProxySwitcher(_ *http.Request) (*url.URL, error) {
    return proxies[random.Intn(len(proxies))], nil
}

// ...
c.SetProxyFunc(randomProxySwitcher)
分布式爬虫

管理独立的和分布式的爬虫最好的办法是你可以将爬虫包装在服务器中。服务器可以是各种服务的比如HTTP,TCP服务器和Google APP Engine。使用自定义的存储实现集中和持久化的cookie来处理访问的url

注意

Colly内置支持Google APP Engine。如果你需要从标准的APP Engine中使用Colly,别忘了调用Collector.Appengine(*http.Request)
一个实现的例子可以从这儿查看

分布式存储

默认情况下,访问的url和cookie数据存储在内存中,这对短生命周期抓取任务很简单。但它对处理大规模和长时间爬取任务有很多限制。
通过实现colly/storage.Storage
接口,Colly可以使用很多后端存储来代替默认的内存存储。查看existing storages.

  • 后端存储
后端存储

Colly可以通过内存存储cookie和访问的url,但它可以被任何实现了colly/storage.Storage的后端存储覆盖

现有的后端存储
In-Memory Backend

Colly 默认的后端存储,可以使用collector.SetStorage() 来覆盖

Redis backend

详细信息查阅redis example

SQLite3 backend
  • 使用多个收集器
使用多个收集器

如果一个爬虫任务足够复杂或者有各种各样的子任务,推荐使用多个收集器。一个很好地例子coursera course scraper
使用了2个收集器,一个处理视图页面列表,另外一个处理课程详情。

注意

在调试中使用collector.ID来区分不同的收集器

克隆收集器

如果收集器中有非常相似的配置,你可以使用Clone() 方法来克隆收集器。Clone() 克隆收集器配置的副本,但不会添加回调函数。

c := colly.NewCollector(
    colly.UserAgent("myUserAgent"),
    colly.AllowedDomains("foo.com", "bar.com"),
)
// Custom User-Agent and allowed domains are cloned to c2
c2 := c.Clone()
在收集器之间传递自定义参数

使用收集器的Request() 方法可以在其他收集器中共享上下文
一个共享上下文的例子:

c.OnResponse(func(r *colly.Response) {
    r.Ctx.Put(r.Headers.Get("Custom-Header"))
    c2.Request("GET", "https://foo.com/", nil, r.Ctx, nil)
}
  • 爬虫配置
爬虫配置

Colly的默认配置已经经过优化,可以在一个任务重抓取数量较小的站点。如果你想抓取上百万个站点,这样的启动不是最好的。这里有一些调整:

使用持久化的后端存储

默认情况下,Colly将cookie和访问过的URL存储在内存中,你可以使用任意自定义的后端存储来替换内置的内存存储。在这里查看更多详情。

对于递归调用的长任务使用异步存储

默认情况下,Colly在请求未完成时会阻塞。所以,在回调函数中递归调用Collector.Visit会产生不断增长的堆栈,使用Collector.Async = true 可以避免(不要忘记了与异步一起使用c.Wait()

禁用或限制连接保持活动状态

Colly使用HTTP keep-alive提高爬取速度,它需要打开文件描述符,所以max-fd限制可以轻松达到长时间运行任务

使用如下代码可以禁用HTTP keep-alive
c := colly.NewCollector()
c.WithTransport(&http.Transport{
    DisableKeepAlives: true,
})
  • 扩展
扩展

扩展是Colly附带的小型辅助工具,插件列表可以在此处获得

用法

以下示例启用随机User-Agent切换器和Referrer setter扩展,并访问httpbin.org两次

import (
    "log"

    "github.com/gocolly/colly"
    "github.com/gocolly/colly/extensions"
)

func main() {
    c := colly.NewCollector()
    visited := false

    extensions.RandomUserAgent(c)
    extensions.Referrer(c)

    c.OnResponse(func(r *colly.Response) {
        log.Println(string(r.Body))
        if !visited {
            visited = true
            r.Request.Visit("/get?q=2")
        }
    })

    c.Visit("http://httpbin.org/get")
}

案例(Examples)

后面文档都只有代码,详情见官网文档

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,332评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,508评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,812评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,607评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,728评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,919评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,071评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,802评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,256评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,576评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,712评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,389评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,032评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,798评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,026评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,473评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,606评论 2 350

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,637评论 18 139
  • Spring Web MVC Spring Web MVC 是包含在 Spring 框架中的 Web 框架,建立于...
    Hsinwong阅读 22,363评论 1 92
  • https://nodejs.org/api/documentation.html 工具模块 Assert 测试 ...
    KeKeMars阅读 6,313评论 0 6
  • 楔子 王者峡谷的迷雾 这座峡谷的天空永远都是血色的,连下的雨的都是红色的。这放肆的红与这峡谷的残酷景色很契合。这片...
    驰星周阅读 487评论 2 3
  • 害怕那朝阳不会升起 害怕那夜空没有星星 害怕明天的日子不会好转 害怕前方的道路永远迷途 害怕,未来没有你的陪伴。 ...
    杨耿耿阅读 360评论 0 0