go语言爬虫无法直接抓取js渲染页面,因net/http仅获初始html;需用chromedp等无头浏览器或逆向ajax接口;goquery链式调用易panic,须检查size();并发需限流并设user-agent。

Go 语言写简单爬虫完全可行,但别指望靠 net/http + goquery 就能直接抓取现代 JavaScript 渲染的页面——那得上无头浏览器,而 Go 生态里没几个靠谱的轻量方案。
为什么用 http.Get 抓不到你看到的网页内容?
很多网站(比如知乎、掘金、新闻聚合页)的正文是通过 JS 动态加载的,http.Get 只拿到初始 HTML,里面可能只有个空 <div id="root"></div>。这时候你用 goquery 查找 .article-content,结果永远是空。
- 先用浏览器开发者工具的 Network 面板,禁用 JS 后刷新,看是否还能显示正文;不能 → 就是 JS 渲染,
http.Client拿不到真实数据 - 检查响应头:
Content-Type是text/html但 body 很短,或含大量script标签 → 大概率服务端只返回壳 - 想绕过?可以试
chromedp,但它需要本地装 Chrome、启动进程、调试超时和上下文生命周期,对“简单爬虫”来说已超纲
goquery 解析 HTML 时常见 panic 场景
goquery 的 Find() 和 Text() 不会报错,但一旦链式调用中某步返回 nil(比如元素不存在),后续调用就会 panic。这不是 bug,是设计使然。
- 错误写法:
doc.Find("h1").Text()—— 如果页面没<h1></h1>,Find()返回空 Selection,Text()仍可调,但Attr()或Children()就可能 panic - 安全写法:始终检查
Size(),例如if s := doc.Find("meta[name=description]"); s.Size() > 0 { desc, _ := s.Attr("content") } - 别依赖
MustXXX系列方法,它们只是把 error 转成 panic,掩盖问题而非解决
并发控制不当导致被封或 429 错误
Go 写爬虫容易陷入“开 100 个 goroutine 一起冲”的误区,但目标站点的反爬逻辑往往就卡在连接频次和来源一致性上。
-
http.DefaultClient的 Transport 默认复用连接,但没限速 —— 你需要自己加time.Sleep或用带缓冲的 channel 控制并发数 - 更稳妥的做法:用
semaphore包(如golang.org/x/sync/semaphore)限制同时活跃请求数,比如设为 3~5 - 别忘了加
User-Agent请求头,否则多数站直接返回 403;用固定 UA 比随机 UA 更不易触发风控(随机反而像脚本) - 响应状态码不是 200 时,别直接
panic,要记录 URL 和状态码,方便排查是网络问题还是反爬拦截
真正麻烦的从来不是怎么发请求或解析 DOM,而是判断这个页面到底“算不算被抓到了”——是内容缺失、结构变更、还是对方悄悄加了 token 签名。这些没法靠框架自动发现,得靠日志、采样和人工比对。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











