使用 net/http 时必须设置 user-agent,否则易被反爬返回403;推荐复用预设头的 http.client,并配合 goquery 解析 html,注意编码、js 渲染、referer 校验及章节排序问题。

用 net/http 发起请求时,必须设置 User-Agent
小说网站基本都有反爬机制,不带 User-Agent 的请求大概率返回 403 或空内容。Go 默认的 http.Client 不带任何头信息,直接调用 http.Get() 几乎必失败。
- 手动构造
http.Request,用req.Header.Set("User-Agent", "Mozilla/5.0...") - 更稳妥的做法是复用一个预设好头的
http.Client,避免每次新建请求都漏设 - 别用网上随手搜的 UA 字符串——部分站点会校验 UA 是否真实,建议从 Chrome 当前版本复制一段
- 如果目标站还校验
Accept或Accept-Encoding,一并加上,例如:req.Header.Set("Accept", "text/html,application/xhtml+xml")
解析 HTML 用 goquery 比原生 html 包快得多
小说页面结构通常嵌套深、标签杂,用标准库 golang.org/x/net/html 手动遍历节点容易出错且开发慢。而 goquery 提供类似 jQuery 的链式选择器,定位章节标题、正文段落非常直观。
初始化并管理阿里云SDK Go 客户端,涵盖 sync.Once 单例、goroutine 安全、endpoint 与 region 配置、VPC 端点及调试。
- 安装:
go get github.com/PuerkitoBio/goquery - 常见写法:
doc.Find("div.content p").Each(func(i int, s *goquery.Selection) { ... }) - 注意:有些小说站正文在
<script></script>标签里动态注入,goquery解析的是静态 HTML,此时需额外处理 JS 渲染逻辑(见下一条) - 别忽略编码问题——若页面是 GBK 编码(如某些老站),
goquery.NewDocumentFromReader前得先用golang.org/x/text/encoding/charmap转 UTF-8
遇到 JS 渲染内容,别硬啃,优先看接口或模拟执行
不少新小说站(尤其微信小程序导流来的)把正文藏在 AJAX 接口里,或者用 eval(unescape(...)) 动态生成 DOM。这时候硬解析 HTML 是死路。
- 打开浏览器开发者工具 → Network → 刷新页面 → 找带“chapter”、“content”、“novel”字样的 XHR/Fetch 请求,复制其 URL 和必要 header(如
X-Requested-With) - 如果接口有签名或时间戳参数,抓包看 JS 怎么算的,用 Go 复现对应逻辑(比如用
crypto/md5拼接字符串再 hex 编码) - 极少数必须跑 JS 的场景,可用
dop251/goja(轻量 JS 引擎)执行关键解密函数,但别试图用它加载完整网页 —— 成本远高于分析接口 - 警惕 Referer 校验:有些接口只接受来自特定域名的请求,记得在 request header 中带上
Referer: https://example.com/
保存文本时,章节顺序和文件名容易乱
爬下来的内容如果直接按请求顺序写文件,最终目录里可能是“第10章.txt”排在“第2章.txt”前面,阅读体验极差。
- 提取章节序号时别只靠字符串截取,用正则更稳:
regexp.MustCompile(`第(\d+)章`).FindStringSubmatchIndex - 写文件前统一格式化为固定位数,比如
fmt.Sprintf("%04d-%s.txt", chapterNum, title),确保排序正确 - 别在循环里频繁
os.Create+defer f.Close()—— defer 在函数退出才触发,大量并发时可能耗尽文件描述符;改用os.WriteFile或显式Close - 如果小说站分卷,先爬目录页拿到所有卷链接,再逐卷处理,比全局混爬更容易维护结构
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!










