先说说这365大千世界是个啥
每天早上睁开眼,我第一件事不是刷朋友圈,而是打开365大千世界看两分钟,这玩意儿就像个万花筒,今天给你看深海发光的水母,明天带你飞越撒哈拉沙漠上空,后天又钻进了亚马逊雨林拍树懒,内容确实够丰富,365天不重样,名副其实的“大千世界”。
但问题来了——视频不能离线看,地铁里信号差的时候,那画质卡得能让人抓狂,我寻思着,能不能写个小工具,把这些视频批量下载到本地呢?
为什么选Go语言来干这活儿
说实话,一开始我考虑过Python,毕竟爬虫界老大哥,但仔细一想,Go语言编译成单个可执行文件,丢到服务器上就跑,不像Python还得装一堆依赖,而且Go的并发模型写下载器简直是天作之合——一个视频一个goroutine,互不干扰。
还有个关键点:365大千世界的视频地址是动态加密的,需要模拟签名算法,Go的标准库虽然不像Python那么“开箱即用”,但配合正则表达式和JSON解析,完全够用,最重要的是,Go写的代码不容易被反爬虫机制识别,因为HTTP头和行为模式更像原生请求。

动手前的准备工作
第一步:摸清视频地址规律
我随便打开一个视频页面,按F12调出开发者工具,盯了半天Network面板,发现视频链接藏在__NEXT_DATA__这个JSON里,结构大概是:
{
"props": {
"pageProps": {
"videoInfo": {
"playUrl": "https://cdn.365world.com/xxx.mp4"
}
}
}
}
这个JSON是服务端渲染时直接嵌入HTML的,虽然做了urlencode,但解码后就能拿到直链。关键点在于,链接里有个expires参数,24小时内有效——所以下载必须趁热。
第二步:搞定模拟登录
有些高清视频需要VIP权限,我抓了下登录接口,发现它是基于JWT的,用Go写个简单的POST请求,带上用户名密码,拿到token再存成cookie,后续请求就畅通无阻了。唯一的坑是登录时有RSA加密,需要把公钥从JS文件里抠出来,配合crypto/rsa包才能搞定。
代码实现:从零到能跑
核心下载模块
func downloadVideo(videoID string) error {
// 1. 构造页面URL
pageURL := fmt.Sprintf("https://www.365world.com/video/%s", videoID)
// 2. 发起GET请求
resp, err := http.Get(pageURL)
if err != nil {
return err
}
defer resp.Body.Close()
// 3. 解析HTML中的__NEXT_DATA__
body, _ := io.ReadAll(resp.Body)
re := regexp.MustCompile(`__NEXT_DATA__.*?>(.*?)</script>`)
matches := re.FindStringSubmatch(string(body))
if len(matches) < 2 {
return errors.New("未找到视频数据")
}
// 4. 从JSON中提取playUrl
var data map[string]interface{}
json.Unmarshal([]byte(matches[1]), &data)
playURL := data["props"].(map[string]interface{})["pageProps"].(map[string]interface{})["videoInfo"].(map[string]interface{})["playUrl"].(string)
// 5. 直接下载
return saveFromURL(playURL, videoID+".mp4")
}
这个流程看着简单,但踩了不少坑,之前有半年时间,签名算法变了,直接按老方法拿到的URL是404,后来抓了个包对比旧链接和新链接,发现多了一个sign=md5(ts+videoid+私钥)的参数,果断把加密逻辑硬编码到工具里,才算恢复正常。
并发控制与断点续传
下载20个视频时,如果串行得等半小时,用goroutine加sync.WaitGroup,同时下载5个,配合context.Context控制超时,体验直接拉满,断点续传用的是HTTP的Range头,每次先查本地文件大小,再续传剩余部分——服务器端支持得很干脆,响应码206就说明成功了。
func downloadRange(url, filepath string, offset int64) error {
req, _ := http.NewRequest("GET", url, nil)
req.Header.Set("Range", fmt.Sprintf("bytes=%d-", offset))
resp, err := http.DefaultClient.Do(req)
if err != nil {
return err
}
f, _ := os.OpenFile(filepath, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
_, err = io.Copy(f, resp.Body)
return err
}
视频合并:别急着删除临时文件
365大千世界的视频分P推流,每集有十来个独立片段,需要按顺序合并,用ffmpeg命令最省事,Go里调exec.Command就行。注意合并前要生成一个包含所有文件名的文本列表,格式是file 'part01.mp4',然后一行命令搞定:
cmd := exec.Command("ffmpeg", "-f", "concat", "-safe", "0", "-i", "list.txt", "-c", "copy", "output.mp4")
cmd.Run()
实际使用中的几个坑
反爬虫的“软刀子”
有一阵子下载频繁了,直接收到验证码弹窗,因为我的User-Agent一直没换,被识别为bot了,后来随机伪装成Chrome和Safari的UA,再加上每3秒sleep一下,终于消停了。
视频清晰度的“文字游戏”
页面显示“1080P”,但实际上直链分辨率只有720P,后来发现,__NEXT_DATA__里还有个qualityLevels数组,只有特定会员等级才能解锁高码率,普通用户最高只能拿到720P,这算是个潜规则——写工具时没必要纠结,该拿什么就拿什么。
本地存储的“焦虑”
20个高清视频下来,80GB空间说没就没了,所以我加了自动压缩功能,转成H.265编码,体积能缩小40%,画质几乎无损(肉眼看不出来,至少我这种近视眼认不出来)。
写在最后
现在我的Go小工具已经稳定跑了三个多月,每天定时凌晨下载当天的视频,存到NAS里,周末窝沙发上,用电视端播放器连续看一整天,那感觉比追剧爽多了——毕竟纪录片的世界,每一帧都不带重样的。
哪天你也被365大千世界的内容馋到了,不妨试试自己写个下载器,Go语言的学习曲线不算陡,网上文档一大堆,遇到坑就多翻翻go.dev的官方博客,要是卡在加密或者并发上,可以翻翻GitHub上那些开源项目,比如yt-dlp的Go移植版,总能找到灵感。
工具嘛,好用就行,至于代码漂不漂亮,谁在乎呢?能用就行,你说对不?
本文来自作者[kyadmin]投稿,不代表be365立场,如若转载,请注明出处:http://hljbesthome.com/nengyuan/2240.html
评论列表(4条)
我是be365的签约作者“kyadmin”!
希望本篇文章《365大千世界视频下载,我用Go语言写了个工具,结果真香了》能对你有所帮助!
本站[be365]内容主要涵盖:be365,be365网站,be365网址,ball365体育,Be365排名
本文概览:先说说这365大千世界是个啥每天早上睁开眼,我第一件事不是刷朋友圈,而是打开365大千世界看两分钟,这玩意儿就像个万花筒,今天给你看...