go的net/http默认无超时,需自定义http.client并设置timeout、idleconntimeout和tlshandshaketimeout;反爬需加user-agent;goquery不执行js,仅解析原始html;注意网页编码与选择器大小写及嵌套层级;并发需用channel限流。

用 net/http 发起请求但返回空或超时?
Go 原生 http.Client 默认不带超时,遇到 DNS 卡住、服务无响应,Get 会一直挂起。这不是 bug,是设计选择——你得自己控制。
- 必须显式设置
Timeout,推荐拆成Timeout(总耗时)、IdleConnTimeout(连接复用空闲时间)和TLSHandshakeTimeout(TLS 握手)三个字段 - 别直接用
http.Get,它用的是默认全局 client,无法设超时;改用自定义&http.Client{Timeout: 10 * time.Second} - 如果目标站有反爬(比如返回 403),大概率是没带
User-Agent;加到req.Header.Set("User-Agent", "Mozilla/5.0")再试
解析 HTML 时 goquery 找不到元素?
goquery 是 jQuery 风格封装,但它不执行 JS,也不等页面动态渲染——它只处理你拿到的原始 HTML 字符串。很多“找不到”本质是 HTML 根本没那部分结构。
- 先用
fmt.Println(htmlBody)或写入文件,人工确认目标内容是否真在响应里;若不在,说明是前端 JS 渲染,goquery无解,得换 Puppeteer 或 Playwright - 注意文档编码:中文站常见
charset=gb2312,但 Go 的net/http默认按 UTF-8 解析,会导致乱码进而 selector 失效;用golang.org/x/net/html+golang.org/x/text/transform手动转码 -
Find("div.item")返回空?检查是否漏了空格或大小写:class="Item"和.item不匹配;也可能是嵌套层级比你预期深,用Children()或Parents()调试路径
并发抓取时被封 IP 或连接数爆炸?
Go 的 goroutine 轻量,但不等于能无脑开 1000 个 http.Get。操作系统级连接限制、目标站限流、DNS 查询排队都会立刻暴露。
- 用带缓冲的 channel 控制并发数,比如
sem := make(chan struct{}, 10),每次请求前sem ,结束后 <code> -
http.Transport必须复用:设置MaxIdleConns(全局最大空闲连接)、MaxIdleConnsPerHost(单域名最大),否则每个请求新建 TCP 连接,很快 hit “too many open files” - 加随机延时不是为了“模拟人”,而是错开请求峰;用
time.Sleep(time.Millisecond * time.Duration(rand.Intn(500))),别固定值,固定值容易被识别为扫描器
保存图片或二进制文件时内容损坏?
常见错误是把 response.Body 当字符串读,比如用 ioutil.ReadAll 后再 string() 转,二进制数据一转就废。
- 永远用
io.Copy(dst, resp.Body)直接流转存,dst 是*os.File;不要中间转[]byte或string - 注意
Content-Type和后缀是否一致:若响应头是image/webp,但你硬存成.jpg,浏览器打不开 - 文件名含中文?用
url.PathEscape编码路径,否则os.OpenFile在某些系统上直接失败
真正麻烦的从来不是发请求或选库,而是目标站结构突变、CDN 动态 token、登录态维持这些隐性依赖。写爬虫前先 curl -v 看三遍响应头和 body,比调十次代码更省时间。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











