Colly 实战:抓取 Factbase 演讲全文并保存 JSON

2025-07-14 17:46 更新

从 API 列表 → 逐条详情 → 本地 JSON 文件,一条命令完成 Factbase 演讲全文抓取。零基础也能 5 分钟跑通!

一、整体思路(先背下来)

  1. 列表收集器:调 API 分页拿 slug + 日期
  2. 详情收集器:根据 slug/transcript/xxx 页面
  3. 上下文传递:把日期/文件名随请求一起带过去
  4. 结果输出:每条演讲保存为一个 <日期>_<slug>.json

二、精简中文代码(30 行)

package main


import (
    "encoding/json"
    "fmt"
    "io/ioutil"
    "strconv"


    "github.com/gocolly/colly/v2"
)


// 演讲全文结构
type Speech struct {
    Speaker string `json:"speaker"`
    Text    string `json:"text"`
}


func main() {
    const (
        searchAPI   = "https://factba.se/json/json-transcript.php?q=&f=&dt=&p="
        transcript  = "https://factba.se/transcript/"
    )


    // 1. 列表收集器:只访问 API
    listC := colly.NewCollector(colly.AllowedDomains("factba.se"))


    // 2. 详情收集器:爬详情页
    detailC := listC.Clone()


    // 3. 解析详情页 → 保存 JSON
    detailC.OnHTML("body", func(e *colly.HTMLElement) {
        var speech []Speech
        e.ForEach(".topic-media-row", func(_ int, el *colly.HTMLElement) {
            speech = append(speech, Speech{
                Speaker: el.ChildText(".speaker-label"),
                Text:    el.ChildText(".transcript-text-block"),
            })
        })


        date := e.Request.Ctx.Get("date")
        slug := e.Request.Ctx.Get("slug")
        file := colly.SanitizeFileName(date + "_" + slug + ".json")


        data, _ := json.MarshalIndent(speech, "", "  ")
        _ = ioutil.WriteFile(file, data, 0644)
        fmt.Printf("✅ 已保存 %s 共 %d 段\n", file, len(speech))
    })


    // 4. 解析 API → 触发详情
    stop := false
    listC.OnResponse(func(r *colly.Response) {
        type Resp struct {
            Data []struct {
                Slug string `json:"slug"`
                Date string `json:"date"`
            } `json:"data"`
        }
        var resp Resp
        _ = json.Unmarshal(r.Body, &resp)


        if len(resp.Data) == 0 {
            stop = true
            return
        }


        for _, d := range resp.Data {
            u := transcript + d.Slug
            ctx := colly.NewContext()
            ctx.Put("date", d.Date)
            ctx.Put("slug", d.Slug)
            detailC.Request("GET", u, nil, ctx, nil)
        }
    })


    // 5. 从第 1 页开始,最多 999 页
    for i := 1; i < 1000 && !stop; i++ {
        _ = listC.Visit(searchAPI + strconv.Itoa(i))
    }
}

三、3 步跑通

步骤 命令 说明
① 安装 go mod init factbase && go get github.com/gocolly/colly/v2 一键拉库
② 保存 复制上方代码 → main.go 零配置
③ 运行 go run main.go 终端实时显示保存进度

四、结果示例

本地生成文件:

2023-10-01_trump-ohio-rally.json
2023-09-30_biden-press-briefing.json
...

打开任意 JSON:

[
  {
    "speaker": "Donald Trump",
    "text": "We are going to make America great again..."
  },
  {
    "speaker": "Reporter",
    "text": "Mr. President, what about..."
  }
]

五、常见问题速查

症状 原因 解决
0 条数据 API 无返回 检查网络 / 换代理
文件中文乱码 Windows 默认编码 用 VS Code 打开即可
403 被拦截 缺 UA 加 colly.UserAgent("Mozilla/5.0...")

六、1 分钟扩展

需求 改动 1 行
只爬前 10 页 i < 11
存 CSV 把 json.MarshalIndent 换成 csv.Writer
存 MongoDB 在 OnHTML 里写 collection.InsertOne
以上内容是否对您有帮助:
在线笔记
App下载
App下载

扫描二维码

下载编程狮App

公众号
微信公众号

编程狮公众号