Go并发爬虫核心是可控并发:用带缓冲channel限流(5~20)、http.Client设超时与User-Agent、goquery结构化解析、sync.Map去重、WaitGroup协调完成。

用 Go 实现并发爬虫,核心是利用 goroutine 并发发起 HTTP 请求,配合 channel 控制任务分发与结果收集,再用结构化方式(如 goquery 或标准库 net/html)解析 HTML。关键不在“多”,而在“可控”——避免请求泛滥、重复抓取、阻塞等待和内存泄漏。
控制并发数量,避免被封或压垮目标站
无限制启协程会快速触发连接超时、429 或 IP 封禁。推荐用带缓冲的 channel 作为信号量,限制同时活跃的 goroutine 数量:
- 定义一个容量为 N 的
semaphore := make(chan struct{}, N) - 每个任务开始前
semaphore ,结束时 - N 建议设为 5~20,视目标站点抗压能力与本地资源调整
安全发起 HTTP 请求并处理响应
别直接用 http.Get,要设置超时、User-Agent、重试逻辑:
- 用
http.Client自定义Timeout(如 10 秒)和Transport(可复用连接) - 每次请求加随机延迟(50~300ms),并在 Header 中设置合理
User-Agent - 对 404、403、5xx 等状态码做区分处理,失败时可有限重试(最多 2 次)
- 读取响应体后立即
resp.Body.Close(),防止文件描述符耗尽
结构化解析 HTML,提取目标字段
推荐使用 github.com/PuerkitoBio/goquery(基于 CSS 选择器,简洁高效):
立即学习“go语言免费学习笔记(深入)”;
- 用
goquery.NewDocumentFromReader(resp.Body)加载文档 - 用
doc.Find("h1.title").Text()或doc.Find("a[href]").Each(...)提取内容 - 注意空节点检查:
if len(title) > 0 { ... },避免 panic - 若需解析大量页面且对性能敏感,也可用标准库
net/html手动遍历节点树
协调任务队列、去重与结果汇总
用 channel + map 实现简单但有效的任务调度:
- 启动一个 goroutine 从初始 URL 列表或队列(
chan string)中取任务 - 用
sync.Map或互斥锁保护全局 visited 集合,防止重复抓取 - 解析结果统一发送到
results chan Result,主 goroutine 收集并写入文件或数据库 - 用
sync.WaitGroup等待所有抓取完成,再关闭 results channel
不复杂但容易忽略。重点不是开多少协程,而是让每个环节可中断、可监控、可降级。










