Colly 高并发爬取:百万级站点轻松拿捏
2025-07-11 17:46 更新
默认配置只能“小打小闹”?跟着本文 3 步改配置,让你的 Colly 爬虫从“单车”变“高铁”,稳稳爬百万站点。
一、默认配置的 3 个瓶颈
瓶颈 | 说明 | 风险 |
---|---|---|
纯内存存储 | Cookie + 已爬 URL 全放内存 | 进程挂掉 = 数据清零 |
同步阻塞 | 一次只能发一个请求 | 速度瓶颈 |
长连接 Keep-Alive | 打开文件句柄不释放 | 句柄耗尽,程序崩溃 |
二、3 步优化:代码级“一键升级”
1️⃣ 换持久化存储:断电也不怕
把默认内存存储换成 Redis(或 BoltDB/SQLite 等),已爬 URL 实时落盘。
import (
"github.com/gocolly/colly/v2"
"github.com/gocolly/colly/v2/storage/redisstorage"
)
func main() {
store, _ := redisstorage.New(
&redisstorage.Options{Address: "127.0.0.1:6379"},
)
c := colly.NewCollector()
c.SetStorage(store) // 完成“搬家”
}
小贴士:没有 Redis?用
boltdb.New("crawler.db")
一行搞定本地文件存储。
2️⃣ 开启异步:并发飞起
默认是同步阻塞,改异步后回调不再堆栈爆炸。
c := colly.NewCollector(
colly.Async(true), // 关键开关
)
// 业务逻辑写完后,记得 Wait!
c.OnHTML("a[href]", func(e *colly.HTMLElement) {
e.Request.Visit(e.Attr("href"))
})
c.Visit("https://www.w3cschool.cn/")
c.Wait() // 等待所有 goroutine 结束
- 并发数控制:加
c.Limit(&colly.LimitRule{Parallelism: 16})
防止把目标站打挂。 - 内存保护:
c.SetRequestTimeout(30 * time.Second)
避免慢请求堆积。
3️⃣ 关闭 Keep-Alive:句柄不再爆表
长连接会占用大量文件描述符,百万级任务建议关闭或缩短。
c.WithTransport(&http.Transport{
DisableKeepAlives: true, // 短连接,用完即关
MaxIdleConns: 100, // 如仍需复用,可限制数量
})
三、完整示例:一键启动“高铁模式”
package main
import (
"time"
"github.com/gocolly/colly/v2"
"github.com/gocolly/colly/v2/storage/redisstorage"
)
func main() {
// 1. 持久化存储
store, _ := redisstorage.New(
&redisstorage.Options{Address: "127.0.0.1:6379"},
)
c := colly.NewCollector(
colly.Async(true), // 2. 异步并发
colly.Debugger(nil), // 可选:调试输出
)
c.SetStorage(store)
// 3. 并发与超时
c.Limit(&colly.LimitRule{
Parallelism: 32,
Delay: 200 * time.Millisecond,
})
c.WithTransport(&http.Transport{
DisableKeepAlives: true,
})
// 业务逻辑
c.OnHTML("a[href]", func(e *colly.HTMLElement) {
e.Request.Visit(e.Attr("href"))
})
c.OnResponse(func(r *colly.Response) {
println("抓到", len(r.Body), "字节 →", r.Request.URL)
})
c.Visit("https://www.w3cschool.cn/")
c.Wait()
}
四、运行前检查清单
检查项 | 命令示例 |
---|---|
Redis 是否启动 | docker run -d -p 6379:6379 redis |
文件句柄限制 | ulimit -n 65535 |
Go 版本 ≥ 1.18 | go version |
五、常见问题速查
现象 | 原因 | 解决 |
---|---|---|
too many open files |
句柄耗尽 | 关闭 Keep-Alive 或提高 ulimit |
爬着爬着重启 | 内存存储丢失 | 换 Redis/BoltDB |
速度没提升 | 忘记 Async(true) |
加开关并 c.Wait() |
六、1 分钟实验
- 打开 终端 → 新建
main.go
。 - 复制“完整示例” → 本地或在线 Redis 一键启动。
- 观察终端:并发 32 路输出,速度肉眼可见提升!
以上内容是否对您有帮助:
更多建议: