codecamp

Colly 多收集器:让爬虫分工协作

任务复杂时,把“一个工人”拆成“多个工人”——一个翻目录、一个拿详情,效率翻倍,代码更清爽。

一、为什么要用多个收集器?

想象你在爬 编程狮课程频道

任务 单收集器 多收集器
翻列表页 → 取 1000 门课程链接 逻辑混杂 列表收集器专职翻页
点进详情页 → 拿课程标题/价格 回调地狱 详情收集器专心解析
结果 代码臃肿、难调试 结构清晰、易维护

二、快速上手:3 步完成“分工”

1. 创建两个收集器

package main


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


func main() {
    // ① 列表收集器:只负责翻页 + 提取详情页链接
    listC := colly.NewCollector(
        colly.AllowedDomains("www.w3cschool.cn"),
    )


    // ② 详情收集器:只负责解析课程详情
    detailC := colly.NewCollector(
        colly.AllowedDomains("www.w3cschool.cn"),
    )
}

2. 克隆收集器(配置共享)

如果两个收集器配置几乎一样,用 Clone() 一行搞定:

base := colly.NewCollector(
    colly.UserAgent("编程狮爬虫 1.0"),
    colly.AllowedDomains("w3cschool.cn"),
)
listC := base.Clone()   // 复用 UA 与域名白名单
detailC := base.Clone()

3. 传递上下文(共享数据)

列表页拿到课程 ID 后,传给详情收集器:

// 列表收集器:拿到链接 → 交给详情收集器
listC.OnHTML("a.course-card", func(e *colly.HTMLElement) {
    detailURL := e.Attr("href")
    // 把课程名放进上下文,后续直接取
    ctx := colly.NewContext()
    ctx.Put("courseName", e.Text)
    detailC.Request("GET", detailURL, nil, ctx, nil)
})


// 详情收集器:用上下文里的数据
detailC.OnHTML("h1", func(e *colly.HTMLElement) {
    courseName := e.Request.Ctx.Get("courseName")
    println("课程名:", courseName, " 标题:", e.Text)
})

三、完整示例:爬“编程狮课程”

package main


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


func main() {
    // 公共配置
    base := colly.NewCollector(
        colly.UserAgent("编程狮-多收集器-Demo"),
        colly.AllowedDomains("www.w3cschool.cn"),
    )


    listC := base.Clone()
    detailC := base.Clone()


    // 列表页:翻页 + 发链接
    listC.OnHTML("a.course-item", func(e *colly.HTMLElement) {
        ctx := colly.NewContext()
        ctx.Put("courseName", e.Text)
        detailC.Request("GET", e.Attr("href"), nil, ctx, nil)
    })


    // 详情页:解析
    detailC.OnHTML("h1", func(e *colly.HTMLElement) {
        courseName := e.Request.Ctx.Get("courseName")
        println("抓到课程:", courseName)
    })


    // 从第一页开始
    listC.Visit("https://www.w3cschool.cn/course")
}

运行结果(示意):

抓到课程:Go 入门教程
抓到课程:Python 爬虫实战
...

四、调试小技巧:一眼看出哪个收集器

在日志里加 collector.ID

listC.OnRequest(func(r *colly.Request) {
    println("[列表收集器]", r.URL)
})
detailC.OnRequest(func(r *colly.Request) {
    println("[详情收集器]", r.URL)
})

五、实战选型速查表

场景 推荐做法
列表 + 详情 两个收集器 + Clone()
不同域名/UA 独立 NewCollector
需要上下文 Request(..., ctx)

六、1 分钟动手实验

  1. 打开 Go 环境 → 新建文件。
  2. 复制“完整示例” → 把域名换成你正在学的站点 → 运行。
  3. 观察终端:列表、详情日志是否交替出现。
Colly 存储后端:给爬虫数据安个“家”
Colly 高并发爬取:百万级站点轻松拿捏
温馨提示
下载编程狮App,免费阅读超1000+编程语言教程
取消
确定
目录

关闭

MIP.setData({ 'pageTheme' : getCookie('pageTheme') || {'day':true, 'night':false}, 'pageFontSize' : getCookie('pageFontSize') || 20 }); MIP.watch('pageTheme', function(newValue){ setCookie('pageTheme', JSON.stringify(newValue)) }); MIP.watch('pageFontSize', function(newValue){ setCookie('pageFontSize', newValue) }); function setCookie(name, value){ var days = 1; var exp = new Date(); exp.setTime(exp.getTime() + days*24*60*60*1000); document.cookie = name + '=' + value + ';expires=' + exp.toUTCString(); } function getCookie(name){ var reg = new RegExp('(^| )' + name + '=([^;]*)(;|$)'); return document.cookie.match(reg) ? JSON.parse(document.cookie.match(reg)[2]) : null; }