悠悠楠杉
Golang中实现网络爬虫文件保存:HTTP下载与文件存储策略
go
doc, _ := goquery.NewDocumentFromReader(resp.Body)
title := doc.Find("title").Text()
对于 <meta> 标签中的关键词和描述,可以通过属性选择器精准定位:
go
var keywords, description string
doc.Find("meta[name='keywords']").Each(func(i int, s *goquery.Selection) {
keywords, _ = s.Attr("content")
})
doc.Find("meta[name='description']").Each(func(i int, s *goquery.Selection) {
description, _ = s.Attr("content")
})
正文内容通常位于特定的语义标签中,如 <article>、<div class="content"> 或 <main>。由于不同网站结构差异较大,建议结合 CSS 选择器优先级和文本长度判断来选取最可能包含正文的节点。可以编写一个评分机制,根据标签类型、类名、子节点数量和文本量综合评估。
提取完结构化数据后,下一步是将其保存到本地文件系统。为了便于后续检索和管理,推荐采用按日期分类的目录结构。例如:
data/
└── 2025-04-05/
├── example-com-1678329123.json
└── example-com-1678329456.json
文件命名可基于 URL 的域名和抓取时间戳生成,避免重复。使用 os.MkdirAll 确保目录存在,再通过 os.Create 创建文件并写入 JSON 数据:
go
dir := time.Now().Format("data/2006-01-02")
os.MkdirAll(dir, 0755)
filename := fmt.Sprintf("%s/%s-%d.json", dir, sanitizeURL(url), time.Now().Unix())
file, _ := os.Create(filename)
defer file.Close()
data := map[string]string{
"url": url,
"title": title,
"keywords": keywords,
"description": description,
"body": extractBodyText(doc), // 自定义函数提取正文
"fetched_at": time.Now().Format(time.RFC3339),
}
json.NewEncoder(file).Encode(data)
在整个流程中,异常处理不容忽视。网络请求可能因超时、DNS 解析失败或目标服务器拒绝而中断;HTML 解析可能遇到编码问题;文件写入也可能因磁盘满或权限不足而失败。因此,每一层操作都应包裹适当的错误捕获逻辑,并记录日志以便排查。
此外,考虑到大规模爬取场景,还需引入限流控制。可通过 time.Tick 控制请求频率,或使用带缓冲的通道实现协程池,防止对目标服务器造成过大压力。同时,利用 sync.WaitGroup 协调多个并发任务的生命周期,确保所有下载完成后再退出主程序。
最终形成的爬虫系统不仅具备稳定的数据采集能力,还能将信息以结构化方式长期保存,为数据分析、搜索引擎构建或内容聚合提供坚实基础。Golang 在这一过程中展现出出色的工程实践价值——简洁而不失强大,高效且易于维护。
