codecamp

Colly 请求上下文:让爬虫数据“随身携带”

想在请求之间传递自定义数据?用 Ctx.Put / Ctx.Get 就像给每个请求发一张“身份证”,URL、标题、分类随用随取!

一、示例:

编程狮课程频道,并携带课程分类:

package main


import (
    "fmt"


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


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


    // 1. 请求前把分类写进上下文
    c.OnRequest(func(r *colly.Request) {
        // 假设我们手动给不同课程加分类
        r.Ctx.Put("category", "Go语言")
        r.Ctx.Put("url", r.URL.String())
    })


    // 2. 响应后取出上下文里的数据
    c.OnResponse(func(r *colly.Response) {
        category := r.Ctx.Get("category")
        url      := r.Ctx.Get("url")
        fmt.Printf("分类[%s] → 地址[%s] 已抓取 %d 字节\n",
            category, url, len(r.Body))
    })


    // 3. 开始爬取
    c.Visit("https://www.w3cschool.cn/go")
}

运行结果:

分类[Go语言] → 地址[https://www.w3cschool.cn/go] 已抓取 12345 字节

二、3 个典型使用场景

场景 存什么 代码示例
列表 → 详情 课程名 r.Ctx.Put("title", e.Text)
分布统计 爬虫节点编号 r.Ctx.Put("node", "worker-3")
登录状态 Token r.Ctx.Put("jwt", token)

三、进阶:多收集器共享上下文

列表收集器把数据传给详情收集器:

listC := colly.NewCollector()
detailC := colly.NewCollector()


// 列表收集器:拿到链接后附带标题
listC.OnHTML("a.course", func(e *colly.HTMLElement) {
    ctx := colly.NewContext()
    ctx.Put("title", e.Text)
    detailC.Request("GET", e.Attr("href"), nil, ctx, nil)
})


// 详情收集器:读取标题
detailC.OnHTML("h1", func(e *colly.HTMLElement) {
    title := e.Request.Ctx.Get("title")
    fmt.Println("课程标题:", title)
})

四、常见坑 30 秒排查

原因 解决
取不到值 用错收集器 确保 Ctx.Put 和 Ctx.Get 在同一收集器或正确传递
并发冲突 多个 goroutine 写同一 key 使用唯一 key 或加锁
内存泄露 大量数据塞 Ctx 及时删除或用外部存储

五、1 分钟动手实验

  1. 打开 终端 → 新建 ctx.go
  2. 复制上方“中文注释”代码 → 运行。
  3. 观察终端:URL 和分类被一起打印,数据“随身携带”。
Colly + Redis 持久化:断点续爬与分布式一步到位
Colly 爬虫即服务:一行命令把爬虫变 HTTP API
温馨提示
下载编程狮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; }