Go开发网站爬虫如何逐次追加JSON数据到单个文件不覆盖原有数据
Go 爬虫JSON数据追加存储问题解决
现有代码问题
你当前的代码每次覆盖数据,核心问题如下:
- 全局切片
allInfos初始化时仅分配了长度为1的空间,每次仅修改第0位元素,没有做追加操作 - 启动时读取到的原有JSON数据存到了局部变量
d中,没有赋值给全局的allInfos,历史数据完全没有被复用 - 抓取到新数据后没有把新条目追加到切片,也没有调用
writeJson方法持久化到文件 - 全局
id仅在服务启动时生成一次,后续所有请求都会复用同一个id,不符合每条数据id唯一的需求 - colly的HTML回调注册放在了请求处理函数里,多次注册会导致回调重复执行
修复后完整代码
package main import ( "encoding/json" "fmt" "html/template" "io/ioutil" "log" "math/rand" "net/http" "os" "strings" "time" "github.com/gocolly/colly" ) type Info struct { ID int `json:"id"` Name string `json:"name"` } var tpl *template.Template var allInfos []Info // 初始化随机数种子,保证每次生成的id不重复 func init() { rand.Seed(time.Now().UnixNano()) } func main() { fmt.Println("Started...") // 启动时读取原有JSON数据到全局切片allInfos data, err := ioutil.ReadFile("stocky.json") if err != nil { fmt.Println("读取JSON文件失败,将创建新文件:", err) allInfos = make([]Info, 0) } else { err = json.Unmarshal(data, &allInfos) if err != nil { fmt.Println("JSON解析失败,初始化空切片:", err) allInfos = make([]Info, 0) } } var errTpl error tpl, errTpl = template.ParseGlob("templates/*.html") if errTpl != nil { log.Fatal("模板加载失败:", errTpl) } http.HandleFunc("/mete", hellloHandleFunc) staticHandler := http.FileServer(http.Dir("./css/")) http.Handle("/css/", http.StripPrefix("/css", staticHandler)) log.Fatal(http.ListenAndServe("localhost:8080", nil)) } func hellloHandleFunc(w http.ResponseWriter, r *http.Request) { err := r.ParseForm() if err != nil { log.Println("表单解析失败:", err) return } requestLink := strings.TrimSpace(r.FormValue("input-link")) if requestLink == "" { fmt.Fprint(w, "请求链接不能为空") return } var name string // 每个请求创建独立的colly实例,避免并发冲突 co := colly.NewCollector() co.OnHTML("div#dp", func(p *colly.HTMLElement) { name = p.ChildText("h1#title") }) err = co.Visit(requestLink) if err != nil { log.Println("页面抓取失败:", err) return } // 生成新的唯一id newID := rand.Intn((99999 - 10000) + 10000) // 创建新的Info条目 newInfo := Info{ ID: newID, Name: name, } // 新条目追加到全局切片 allInfos = append(allInfos, newInfo) // 全量数据写入文件持久化 writeJson(allInfos) // 控制台输出当前所有数据 enc := json.NewEncoder(os.Stdout) enc.SetIndent("", " ") enc.Encode(allInfos) fmt.Println("新数据已写入") tpl.ExecuteTemplate(w, "form-copy.html", newInfo) } func writeJson(data []Info) { dataFile, err := json.MarshalIndent(data, "", " ") if err != nil { log.Println("JSON生成失败:", err) return } err = ioutil.WriteFile("stocky.json", dataFile, 0666) if err != nil { log.Println("文件写入失败:", err) } }
核心修改说明
- 启动时直接把原有JSON数据读取到全局切片
allInfos中,保留所有历史数据 - 每次收到请求生成新的唯一id,创建新的Info对象追加到切片
- 每次追加完数据后立即调用
writeJson方法把全量数据写入文件 - 每个请求使用独立的colly实例,避免并发和回调重复注册问题
- 补充了错误处理逻辑,避免异常情况导致服务崩溃
内容的提问来源于stack exchange,提问作者Melisa
相关产品推荐
相关产品推荐

