colly 初始化抓不到页面主因是默认禁js渲染、未设useragent致被拦截;需显式配置ua、处理重定向,js依赖页应换puppeteer;并发需用delay限流而非单纯提parallelism,结果导出推荐channel避免闭包数据竞争。

Colly 初始化时为什么抓不到页面?
常见现象是 c.Visit() 后没触发回调,控制台无日志、c.OnHTML() 完全不执行。根本原因通常是默认不启用 JavaScript 渲染,且未处理重定向或 User-Agent 被拦截。
- 必须显式设置
c.UserAgent,多数网站会拒收空 UA 或 Go 默认 UA(如"colly - https://github.com/gocolly/colly") - 如果目标页依赖 JS 渲染(比如 React/Vue SPA),Colly 本身不执行 JS,得换 Puppeteer 或加 headless Chrome,别硬扛
- 检查 HTTP 状态码:加
c.OnResponse(func(r *colly.Response) { log.Println(r.StatusCode) }),403/429 意味着被反爬,需加延时或代理 - 确保
c.Visit()传入的是完整 URL(含https://),相对路径会静默失败
如何安全地并发采集并避免封 IP?
Colly 默认单 goroutine,开多协程直接调 c.Visit() 会 panic;但盲目设 c.Limit(&colly.LimitRule{DomainGlob: "*", Parallelism: 10}) 又容易触发风控。
- 用
c.Limit(&colly.LimitRule{DomainGlob: "*", Delay: 2 * time.Second})比单纯提高 Parallelism 更稳妥 - 每个采集任务建议用独立
colly.NewCollector()实例,共享全局限流器(colly.NewLimitRules() + c.WithLimitRules())更可控 - 不要在
OnHTML回调里同步发 HTTP 请求(比如下载图片),改用c.Visit()异步调度,否则阻塞 collector - 记录失败 URL 和状态码,失败超 3 次自动暂停该域名 30 秒(用
c.OnError()+time.Sleep())
数据怎么从 Colly 回调里“带出来”到 API 响应?
很多人把结构体变量声明在 main() 外部,靠闭包修改,结果并发下数据错乱或漏采——Colly 回调不是顺序执行的。
- 用 channel 接收解析结果:
ch := make(chan []MyItem, 100),在OnHTML里ch ,主 goroutine 用 <code>select或for range收集 - 避免在回调里直接写数据库或调外部 API,先攒够一批再批量处理(比如每 50 条 flush 一次)
- 如果 API 是 Gin/Echo,别把
colly.Collector实例挂到context里复用——每次请求应新建 collector,否则限流/cookie 会串 - 记得关闭 collector:
defer c.Close(),否则 goroutine 和连接泄露
API 接口返回 JSON 时,如何处理动态字段和空值?
网页结构常变,硬写 doc.Find("div.title").Text() 容易 panic;JSON 序列化时 "" 和 nil 混用又导致前端解析失败。
立即学习“go语言免费学习笔记(深入)”;
- 用
strings.TrimSpace(doc.Find("h1").Text())包一层防空白字符串,再判断 len > 0 - 结构体字段加
json:",omitempty"标签,但注意:零值字段(0, "", false)也会被忽略,必要时用指针类型(*string)显式区分 “空” 和 “未采集” - 采集前先做简单校验:
if doc.Find("body").Length() == 0 { return },避免后续所有Find()返回空对象还继续取文本 - 对关键字段(如 ID、URL)做正则清洗:
regexp.MustCompile(`\s+`).ReplaceAllString(url, ""),防止空格导致后续请求失败
事情说清了就结束。真正难的不是写通 Colly,而是判断哪个环节在丢数据——是网络层被限速、DOM 结构突变、还是你忘了 c.AllowURLRevisit() 导致跳过重复链接。










