You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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)
	}
}

核心修改说明

  1. 启动时直接把原有JSON数据读取到全局切片allInfos中,保留所有历史数据
  2. 每次收到请求生成新的唯一id,创建新的Info对象追加到切片
  3. 每次追加完数据后立即调用writeJson方法把全量数据写入文件
  4. 每个请求使用独立的colly实例,避免并发和回调重复注册问题
  5. 补充了错误处理逻辑,避免异常情况导致服务崩溃

内容的提问来源于stack exchange,提问作者Melisa

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.11 17:00:01