用Golang写个爬虫,把365第一季西瓜视频翻个底朝天—这事儿我真干了
- 汽车
- 2026-08-06 21:59:25
- 89
说实话,写这篇文章之前,我正对着电脑屏幕发呆,起因特简单,上周我妈跟我说:“你不是学编程吗?能不能把那个365第一季西瓜视频里的育儿课给我下下来,我晚上想躺床上看。”我寻思着,这需求不正好练手Golang嘛——毕竟网上那些Python爬虫教程都快烂大街了,用Go写视频站点抓取的文章反而少。
先说清楚:咱聊的是“365第一季”,不是别的
我在网上查了一圈,发现“365”这词儿在西瓜视频里至少对应三种内容:一个是365天不间断更新的Vlog系列,一个是某知识类账号的365节课程合集,还有一个是部老剧,叫《365:逆转命运的一年》的第一季,我把这些全摸了一遍,就用Golang写了几个小工具,挨个试。
您可别嫌我啰嗦,这事儿的难点压根不在“写代码”,而在“摸清西瓜视频的页面结构”,您要是直接拿net/http去Get首页,返回的HTML里根本找不到视频地址——现在都走JS渲染了,数据全藏在__INITIAL_STATE__或者XHR接口里。
咱一步步来:Go里怎么“骗”过西瓜的服务器
第一步:模拟浏览器请求头
我用Golang写了个函数,专门构造带User-Agent和Referer的请求:
func buildRequest(url string) *http.Request {
req, _ := http.NewRequest("GET", url, nil)
req.Header.Set("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36")
req.Header.Set("Referer", "https://www.ixigua.com/")
return req
}
您别看就这么几行,没这俩头,西瓜直接给你返回403,我一开始没加,愣是排查了半天,最后发现是反爬机制在作祟。
第二步:从HTML里抠出JSON数据
拿到页面后,得找那个<script>window._SSR_HYDRATED_DATA_ = {...}</script>标签,我用正则加字符串切割双管齐下:
func extractJSON(html string) (string, error) {
start := strings.Index(html, "window._SSR_HYDRATED_DATA_=")
if start == -1 {
return "", errors.New("没找到数据")
}
cut := html[start+28:]
end := strings.Index(cut, "</script>")
return cut[:end], nil
}
这里有个坑:有时候返回的是转义后的JSON,比如\u002F代表,我用encoding/json的Unmarshal竟然报错——后来发现得先strconv.Unquote处理一圈。
第三步:解析视频ID和播放地址
拿“365第一季西瓜视频”里某个具体的Vlog举例,返回的JSON结构大概是这样的:
| 字段路径 | 含义 | 示例值 |
|---|---|---|
data.videoInfo.videoId |
视频唯一ID | 7103456789012345678 |
data.videoInfo.title |
“365天记录·第1天” | |
data.videoInfo.playUrl |
播放地址 | http://v3-xx.ixigua.com/... |
data.videoInfo.duration |
时长(秒) | 253 |
注意那个playUrl,有时候直接能下载,有时候得再拼个?ratio=16:9&format=mp4之类的参数,我用net/url的Query来拼,省得手写出错。
讲个翻车过程:Go的并发下载反而卡死了
我写了个用goroutine并发下载视频片段的函数,心想“365集多线程还不一会儿就搞定?”结果跑起来,内存直接爆了——因为每路请求都把整个响应体读进内存,后来改成用io.Copy边读边写文件,才稳住。
func downloadSegment(url string, file *os.File) error {
resp, err := http.Get(url)
if err != nil { return err }
defer resp.Body.Close()
_, err = io.Copy(file, resp.Body)
return err
}
这个教训挺实在的:Go虽好,但别乱开goroutine,得用信号量控制并发数,比如最多同时5个。
给真想用Go抓西瓜的朋友几个实在建议
- 别去碰那些要登录才能看的VIP视频,我试了,得携带cookie和动态的签名参数,Go写起来特别繁琐,直接用的
chromedp库才搞定,但那就不算纯Go了。 - 设置好超时,西瓜有时候会卡住连接,用
http.Client{Timeout: 30 * time.Second}放着稳妥。 - 用
gjson库解析嵌套JSON比标准库舒服十倍,是我个人最爱:
videoID := gjson.Get(jsonStr, "data.videoInfo.videoId").String()
最后再说点题外话
我最后确实把我妈要的那集《365第一季西瓜视频》里的育儿课下载下来了,花了大概三分钟写了这堆代码,又花了半小时调试。看着进度条走完,我居然有点恍惚——这编程和生活似的,有时候你觉得是个大工程,拆开了一步步来,其实也就那么回事,您要是也遇到类似的抓取需求,别怕,拿起Golang慢慢试,翻车几次总能跑通。
好了,我得去给我妈把视频导进平板里了,她刚才又在催了。
