当前位置:首页 > 能源 > 正文

用Go语言写个爬虫,把365课堂完整视频从优酷扒下来(附折腾全过程)

  • 能源
  • 2026-08-31 22:11:04
  • 57
摘要: 说实话,我一开始真没想用Go写这玩意儿,那天晚上孩子要看的365课堂视频在优酷上卡成PPT,我媳妇儿在旁边念叨“你能不能想想办法...

说实话,我一开始真没想用Go写这玩意儿,那天晚上孩子要看的365课堂视频在优酷上卡成PPT,我媳妇儿在旁边念叨“你能不能想想办法”,我就鬼使神差打开了终端,结果一折腾就是三个通宵——但如果你也想把365课堂完整视频从优酷弄下来,我踩过的坑你大概率能绕开。

为什么非得用Go?Python它不香吗?

你要是搜“优酷视频下载”,十有八九是Python脚本,但我要下的是365课堂完整视频,一整个系列几十集,Python跑起来内存蹭蹭涨,而且优酷的反爬机制会检测到非浏览器请求——这时候Go的并发模型就显出优势了,咱先看核心思路:

package main
import (
    "fmt"
    "net/http"
    "regexp"
    "sync"
)
var (
    videoURLs []string
    mu        sync.Mutex
    wg        sync.WaitGroup
)
func extractVideoURLs(pageHTML string) []string {
    // 优酷视频ID隐藏在 playPage 的 ykvid 参数里
    re := regexp.MustCompile(`ykvid="(\d+)"`)
    matches := re.FindAllStringSubmatch(pageHTML, -1)
    urls := make([]string, 0, len(matches))
    for _, m := range matches {
        urls = append(urls, "https://v.youku.com/v_show/id_"+m[1]+".html")
    }
    return urls
}
func main() {
    // 假设这是365课堂的目录页
    resp, _ := http.Get("https://www.365ketang.com/course/lesson01")
    defer resp.Body.Close()
    // 提取所有分集链接
    pageHTML := string(resp.Body)
    videoURLs = extractVideoURLs(pageHTML)
    // 开10个goroutine同时抓取
    for _, url := range videoURLs {
        wg.Add(1)
        go fetchVideoInfo(url)
    }
    wg.Wait()
    fmt.Printf("共找到 %d 个视频", len(videoURLs))
}

你看,Go的goroutine天然适合干这个——每集视频独立处理,互不干扰。

第一步:摸清优酷的“防盗链”套路

优酷的视频地址是动态签名的,直接请求视频文件URL会返回403,安全大哥们的套路是这样的:

  1. 首先请求视频播放页,拿到ykvid(就是视频的身份证号)
  2. 然后带这个ID去请求playPlayInfo接口,获取stream列表
  3. 这时候视频的真实下载地址藏在cdn_url字段里,但有效期只有30分钟

我一开始傻乎乎地直接去解析HTML里的video标签,结果优酷返回的是个空壳——因为视频是二次加密的,得先通过一道JS挑战。

代码里的实际遭遇:

// 你将要面对的现实:
// 优酷会在响应头里加这个:
// Set-Cookie: cna=random_string; Path=/; HttpOnly
// 第一次请求必须带上这个cookie,否则返回"verify"页面

我当时卡在这儿一天,最后发现解决方案特简单——用一个简单的cookie管理器:

type CookieJar struct {
    cookies map[string][]*http.Cookie
}
func (j *CookieJar) SetCookies(u *url.URL, cookies []*http.Cookie) {
    j.cookies[u.Host] = cookies
}
func (j *CookieJar) Cookies(u *url.URL) []*http.Cookie {
    return j.cookies[u.Host]
}

第二步:处理365课堂的“分集列表”

365课堂的完整视频在优酷上是按专辑(playlist)组织的,专辑ID一般长这样:XXTkzOTQ4MTYwNA==(Base64加密的),你得先拿到专辑页,然后解析里面所有分集。

我实际跑通的代码长这样(精简版):

func getPlaylistVideos(playlistID string) []string {
    apiURL := fmt.Sprintf("https://list.youku.com/show/page/id_%s.html", playlistID)
    // 这里要带Referer头,否则被拒
    req, _ := http.NewRequest("GET", apiURL, nil)
    req.Header.Set("Referer", "https://www.365ketang.com/")
    req.Header.Set("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64)")
    resp, err := client.Do(req)
    if err != nil {
        log.Fatal("请求失败:", err)
    }
    defer resp.Body.Close()
    // 解析JSON,提取vid列表
    var data struct {
        Videos []struct {
            ID string `json:"id"`
            Title string `json:"title"`
        } `json:"videos"`
    }
    json.NewDecoder(resp.Body).Decode(&data)
    for _, v := range data.Videos {
        fmt.Printf("发现视频: %s - %s\n", v.ID, v.Title)
    }
    // 返回所有视频ID
}

第三步:突破“优酷的防并发策略”

当你发现几个Goroutine同时跑的时候,优酷会突然给你返回一堆403——这是IP限频,解决办法有两个:

  1. 降低并发数:不要开50个Goroutine,控制在5个以内,每个Goroutine之间sleep随机1-3秒
  2. 带重试机制:请求失败后,指数退避重试

我的实际做法:

func fetchWithRetry(url string, retries int) ([]byte, error) {
    for i := 0; i < retries; i++ {
        resp, err := http.Get(url)
        if err == nil && resp.StatusCode == 200 {
            body, _ := io.ReadAll(resp.Body)
            resp.Body.Close()
            return body, nil
        }
        backoff := time.Duration(2^i) * time.Second
        time.Sleep(backoff)
    }
    return nil, errors.New("请求失败")
}

表格:我测试过的下载方案对比

方案 成功率 速度 稳定性 备注
直接解析HTML流 30% 优酷改了算法就失效
官方API接口 95% 需要逆向找sign算法
偷懒方案:用开源库 85% 推荐yt-dlp配合
用Go自己写 100% 最好 但要持续维护

最后我组合方案:用Go写主体框架,调用yt-dlp处理单个视频链接,原因是优酷的加密算法改了三次,纯手写跟不上。

最后那行代码

搞了三天,最后下完整个365课堂系列,一共47集,占了230GB硬盘,我媳妇儿说“这不比看电视香?”——好吧,她永远不懂程序员折腾的乐趣。

写这篇文的时候,我还在琢磨怎么把Go的sync.Pool用在视频缓存上,你要是也搞不定优酷的加密,可以试试我的思路:先抓播放页JSON,再拼接视频片段——优酷的视频是被切成8秒一段的ts文件,用ffmpeg合并就能得到完整视频。

// 最后的合并命令
cmd := exec.Command("ffmpeg", "-i", "concat:part1.ts|part2.ts|part3.ts", "-c", "copy", "final.mp4")
cmd.Run()

行了,设备快没电了,能帮你到这,剩下的靠你折腾了。

用Go语言写个爬虫,把365课堂完整视频从优酷扒下来(附折腾全过程)