codecamp

Colly 实战:批量抓取 OpenEdX 课程信息

想一键爬完 IndonesiaX(或其他 OpenEdX 站点)的全部课程?官方示例 70+ 行已精简成 20 行中文注释版,复制即可跑,直接输出 JSON!

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

  1. 列表页:从 /courses 开始 → 找所有 /courses/xxx 链接
  2. 详情页:解析标题、起止时间、课程号等字段
  3. 结果输出:一次性导出 JSON,Excel 直接打开

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

package main


import (
    "encoding/json"
    "fmt"
    "strings"
    "time"


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


// 课程结构体
type Course struct {
    CourseID  string     `json:"课程ID"`
    Name      string     `json:"课程名称"`
    Number    string     `json:"课程编号"`
    StartDate *time.Time `json:"开始时间"`
    EndDate   *time.Time `json:"结束时间"`
    URL       string     `json:"课程链接"`
}


func main() {
    c := colly.NewCollector(
        colly.AllowedDomains("www.indonesiax.co.id", "indonesiax.co.id"),
        colly.CacheDir("./cache"), // 断点续爬
    )


    var courses []Course


    // 1. 课程列表页 → 进入详情
    c.OnHTML(`a[href^="/courses/"]`, func(e *colly.HTMLElement) {
        e.Request.Visit(e.Attr("href"))
    })


    // 2. 详情页解析
    c.OnHTML(`.course-info`, func(e *colly.HTMLElement) {
        title := strings.TrimSpace(strings.Split(e.ChildText(".course-title"), "\n")[0])
        id    := e.ChildAttr("input[name=course_id]", "value")
        start, _ := time.Parse("Jan 02, 2006", e.ChildText(".start-date"))
        end,   _ := time.Parse("Jan 02, 2006", e.ChildText(".final-date"))


        courses = append(courses, Course{
            CourseID:  id,
            Name:      title,
            Number:    e.ChildText(".course-number"),
            StartDate: &start,
            EndDate:   &end,
            URL:       "https://www.indonesiax.co.id/courses/" + id,
        })
    })


    // 3. 启动
    c.Visit("https://www.indonesiax.co.id/courses")


    // 4. 输出 JSON
    jsonData, _ := json.MarshalIndent(courses, "", "  ")
    fmt.Println(string(jsonData))
}

三、3 步跑通

步骤 命令/操作 说明
① 安装依赖 go mod init openedx && go get github.com/gocolly/colly/v2 一键拉库
② 保存文件 复制上方代码 → main.go 零配置
③ 一键爬取 go run main.go > courses.json 生成 JSON,可导入 Excel

四、结果示例(courses.json)

[
  {
    "课程ID": "course-v1:ITB+CS101+2024_T1",
    "课程名称": "Pemrograman Dasar",
    "课程编号": "CS101",
    "开始时间": "2024-01-15T00:00:00Z",
    "结束时间": "2024-05-15T00:00:00Z",
    "课程链接": "https://www.indonesiax.co.id/courses/course-v1:ITB+CS101+2024_T1"
  }
  // …更多课程
]

五、常见问题速查

症状 原因 解决
0 条数据 选择器失效 浏览器 F12 更新 .course-title 等
日期解析失败 格式变化 改 time.Parse("2006-01-02", ...)
403 被拦截 缺 UA / 反爬 加 colly.UserAgent("...")

六、1 分钟换站

目标站点 改动 2 处
edX.org 把域名和 /courses 换成 www.edx.org/courses
慕课中国 域名 + 选择器同步调整
Colly 实战:批量下载 Instagram 公开图片
Colly 实战:3 分钟爬完 Reddit 热帖
温馨提示
下载编程狮App,免费阅读超1000+编程语言教程
取消
确定
目录

关闭

MIP.setData({ 'pageTheme' : getCookie('pageTheme') || {'day':true, 'night':false}, 'pageFontSize' : getCookie('pageFontSize') || 20 }); MIP.watch('pageTheme', function(newValue){ setCookie('pageTheme', JSON.stringify(newValue)) }); MIP.watch('pageFontSize', function(newValue){ setCookie('pageFontSize', newValue) }); function setCookie(name, value){ var days = 1; var exp = new Date(); exp.setTime(exp.getTime() + days*24*60*60*1000); document.cookie = name + '=' + value + ';expires=' + exp.toUTCString(); } function getCookie(name){ var reg = new RegExp('(^| )' + name + '=([^;]*)(;|$)'); return document.cookie.match(reg) ? JSON.parse(document.cookie.match(reg)[2]) : null; }