反爬核心是构造合规请求包而非模拟人,关键在User-Agent/Referer组合、Sec-Ch-Ua补全、禁用HTTP/2、定制TLS指纹、独立CookieJar及按域名限流。

反爬不是模拟人,是绕过规则触发点
Go 爬虫被封,90% 不是因为“不像人”,而是请求在 WAF(如 Cloudflare)或后端中间件上触发了明确的规则:HTTP/2 启用、TLS 指纹异常、Header 缺失、Cookie 域不匹配、Referer 与 UA 组合矛盾。核心逻辑是把每个请求当成一个「合规信号包」来构造,而非堆砌行为模拟。
关键控制点集中在请求层可批量干预的五个维度:User-Agent + Referer 组合校验、Sec-Ch-Ua 等 Chromium 必带 header 补全、http.Transport 层禁用 HTTP/2 并替换 TLS 指纹、colly.CookieJar 替代标准 net/http/cookiejar、按域名独立配置 rate.Limiter。
不要试图让单个请求“全能”,而是让整个请求流在目标站点的风控模型里始终处于灰度区——既没被标记为 bot,也没被当作高危流量拦截。
为什么不能共用一个 http.Client 实例打所有站点
标准 http.Client 复用连接池 + 共享 Transport,但不同站点对 TLS 握手细节、HTTP 版本、重试策略容忍度差异极大。比如 A 站接受 TLS 1.3 + ESNI,B 站却因识别出非浏览器 TLS 扩展直接返回 403;C 站依赖 Set-Cookie 的 Secure 标志做会话校验,而你的 transport 没启用 TLS,cookie 就被静默丢弃。
实操建议:
- 每个目标域名配独立
http.Client,transport 单独初始化,禁用ForceAttemptHTTP2: false - 用
github.com/zmap/zcrypto/tls或github.com/senghoo/golang-fingerprint替换原生crypto/tls,传入定制指纹 - UA 和 Referer 必须动态生成:UA 从预定义 slice 随机取,Referer 严格设为上一级页面 URL(例如抓
/news/123前,先 GET/news/,再把该响应 URL 设为 Referer)
Cookie 管理失效的三个隐蔽原因
很多 Go 爬虫看似设置了 cookiejar.New(nil),但实际 cookie 没生效,常见于以下场景:
第一,标准 net/http/cookiejar 不支持 Domain 字段的宽松匹配(如 Set-Cookie: domain=.example.com 被当成无效 domain),导致 cookie 存不进 jar;第二,SameSite=Strict 或 Secure 的 cookie 在非 HTTPS 请求中被浏览器策略拒绝,而你的 transport 没走 TLS,却还在发 HTTP 请求;第三,多个 goroutine 并发写同一个 jar,发生竞争丢失。
正确做法:
- 用
colly.NewCollector().Jar,它内部做了 Domain 归一化和路径匹配修正 - 首次访问前手动注入可信 cookie(如从浏览器导出的
cf_clearance),调用c.SetCookies(url, cookies) - 确保 transport 的
TLSClientConfig已启用,且请求 URL 是https://开头,否则Securecookie 直接被忽略
并发调度必须按域名隔离限流
全局统一限流(比如所有请求都 time.Sleep(1s))既低效又危险:对静态资源多的站是浪费,对 API 密集型站又可能触发 QPS 熔断。WAF 通常按 Host + CF-Ray(Cloudflare 请求 ID)+ 源 IP 组合做速率统计,跨域名混发请求等于主动帮对方聚合风控特征。
推荐方案:
- 用
golang.org/x/time/rate.Limiter,为每个Host创建独立 limiter 实例,比如limiters["example.com"] = rate.NewLimiter(rate.Every(2*time.Second), 1) - 在请求前加
limiter.Wait(ctx),而不是time.Sleep,避免 goroutine 阻塞 - 监控响应头里的
CF-Ray和X-RateLimit-Remaining,当值突降或出现429时,自动将该域名 limiter 的Every周期翻倍
真正难的不是并发量,而是让每个域名的请求节奏在对方系统里看起来像一个真实用户在翻页——有停顿、有回退、有资源加载延迟。这些细节藏在 transport 层和限流策略里,不在 goroutine 数量上。



















