最近帮朋友做PPT365的素材整理,他非要我从百度视频里扒点东西下来,我一听,这不就是写个爬虫嘛,但说实话,百度视频的反爬机制这两年升级了不少,再加上PPT365对视频格式还有点挑——得是m3u8或者mp4,还得控制在10M以内,今天就拿Golang聊聊我是怎么一步步搞定的,全程用费曼思路,把技术细节拆成大白话。
先从需求说起:PPT365到底要什么?
PPT365这个软件,说白了就是个傻瓜式PPT生成器,它支持插入视频,但限制挺多:
| 要求项 | 具体限制 | 我的踩坑经验 |
|---|---|---|
| 视频格式 | 必须是mp4或m3u8 | 百度视频的m3u8文件嵌套复杂,我差点放弃 |
| 文件大小 | 不超过10MB | 抓下来的视频动不动就50M+,得用ffmpeg压缩 |
| 来源稳定性 | 不能失效太快 | 百度视频的临时链接通常20分钟内有效 |
| 版权风险 | 建议只用于个人学习 | 我朋友说是做公司内部分享,但大家别乱用 |
所以核心问题就是:如何从百度视频拿到一个符合PPT365规范的视频文件。
第一步:分析百度视频的抓取难点
百度视频其实不是一个独立的视频网站,它是个聚合平台,你搜一个关键词,它返回的是其他站点的视频链接——比如爱奇艺、腾讯视频、B站这些,所以直接抓百度视频的页面,拿到的是个“导航页”,不是真正的视频流。
我用Golang写了这么一段代码来模拟请求:
package main
import (
"fmt"
"net/http"
"github.com/PuerkitoBio/goquery"
)
func main() {
url := "https://v.baidu.com/v?word=PPT教程"
client := &http.Client{}
req, _ := http.NewRequest("GET", url, nil)
req.Header.Set("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36")
resp, _ := client.Do(req)
defer resp.Body.Close()
doc, _ := goquery.NewDocumentFromReader(resp.Body)
doc.Find(".video-list-item").Each(func(i int, s *goquery.Selection) { _ := s.Find(".title a").Attr("href")
fmt.Println("找到视频:", title)
})
}
跑完发现,返回的链接全是短链,点进去才是真正的视频页,而且百度对IP有频率限制,一分钟超过30次请求就封IP,我干脆用代理池加Goroutine控制并发——每秒只发5个请求,每个请求换一个代理IP。
第二步:从视频页提取真实播放地址
拿到视频详情页后,真正的难题来了,百度视频用的播放器技术版本很老——大部分是Flash时代的“vid”参数解码,我看了下HTML源码,发现播放器初始化时的JavaScript里藏着一串加密的字符串。
当时我试了三种方法:
- 直接解析页面里的mp4标签 —— 90%的页面压根不写死下
- 抓取Flash的xml配置 —— chrome开发者工具里能看到类似于
https://vdn.apps.cdn.baidu.com/video/index.xml?vid=xxx这种请求 - 模拟播放器的解密逻辑 —— 这是最稳妥的路子,但Golang里得自己写解密函数
最终我选了方法2的升级版:用golang.org/x/net/html解析DOM树,找到<script>标签里vid的值,然后拼出xml请求地址。
// 简化版:提取vid
re := regexp.MustCompile(`vid="(\d+)"`)
vid := re.FindStringSubmatch(htmlContent)
xmlUrl := fmt.Sprintf("https://vdn.apps.cdn.baidu.com/mcp/media/video/playform/config?vid=%s&auto=1", vid[1])
// 解析xml拿到真实地址
xmlResp, _ := client.Get(xmlUrl)
decoder := xml.NewDecoder(xmlResp.Body)
这里有个坑:百度视频的xml返回的内容里,视频地址是经过Base64编码的,而且时长字段单位是毫秒,我的代码里要加个decodeBase64()函数,不然拿到的直接是一堆乱码。
第三步:解决格式转换和大小压缩
拿到真实的mp4地址后,我测了下——平均一个3分钟的教程视频,大小在30M到80M之间,PPT365要求10M以内,所以必须压缩。
我的解决方案是调用ffmpeg命令行工具,用Golang的os/exec包来执行:
cmd := exec.Command("ffmpeg",
"-i", inputPath,
"-vcodec", "libx264",
"-crf", "28",
"-preset", "fast",
"-acodec", "aac",
"-b:a", "64k",
"-vf", "scale=640:-2",
"-fs", "9M", // 限制文件大小在9M以内
outputPath,
)
cmd.Run()
-crf 28这个值很关键——网上很多人用18(高质量),但PPT365的播放器清晰度有限,压到28基本上看不出画质损失,体积却能省一半,另外-fs 9M参数是给ffmpeg的一个硬性限制,超过9M就直接报错,防止卡住。
第四步:自动化流程与异常处理
手动抓一个视频还行,但朋友要的是批量抓取——他列了20个关键词,每个要抓前5个视频,这时候就得走自动化了。
我管这个叫“三阶段管道”:

- 第一阶段:搜关键词,获取视频列表页URL → 用Goroutine并发请求
- 第二阶段:解析真实视频地址 → 用带重试机制的HTTP客户端
- 第三阶段:下载+压缩 → 用带进度条的下载器
异常情况我遇到过很多:视频源突然失效、403禁止访问、XML解析失败、ffmpeg崩溃……所以每个阶段我都加了最大重试3次,每次重试间隔2秒的机制。
type Task struct {
Keyword string
Index int
URL string
Status string
}
func worker(tasks <-chan Task, results chan<- Result) {
for task := range tasks {
// 带重试的抓取逻辑
for i := 0; i < 3; i++ {
if success := fetchVideo(task); success {
results <- Result{task, "ok"}
break
}
time.Sleep(2 * time.Second)
}
}
}
跑了一天半,抓了87个视频,成功压缩到PPT365可用的有63个,成功率73%左右,失败的要么是源站主动屏蔽了,要么是视频时长太长(超过10分钟)压不到9M以内。
一些不得不说的注意事项
并发别开太大
我第一次直接起了100个Goroutine,结果电脑CPU飙到100%,而且百度直接把我IP封了6小时,后来改成10个并发,加上随机延迟1-3秒,稳定多了。
磁盘空间预警
每个临时文件下载下来可能30M,压缩完得保留原文件和压缩文件,20个视频同时跑,我的笔记本电脑120G硬盘直接红了,后来改成边下载边压缩,压缩完立刻删原文件。
法律红线
这个必须得说清楚——百度视频的内容版权归原始上传者所有,我朋友的公司是做内部分享PPT,而且只抓了百度公开内容,但我还是建议大家在代码里加个免责提示。
最终的代码长什么样
实话实说,我没写出一个完美的一键脚本,因为百度视频的结构太动态了——比如有时候视频地址藏在JSON-LD里,有时候在JS变量里,还有时候在iframe里,我的做法是写了一个适配器模式:
- 先检测页面结构类型
- 再调用对应的解析器
- 如果都不匹配,就回退到通用的正则匹配
这样虽然代码量多了200多行,但兼容性好了不少,实际测试下来,能覆盖百度视频大概85%的页面。
要是你只需要抓一两个视频,其实直接用浏览器开发者工具手动找视频源地址,比写代码快多了,我写这个工具,纯粹是被朋友逼出来的。
哦对了,如果你用Golang 1.22以后的版本,记得把http.Server换成http.Client的新配置方式——http.Request.Clone()在并发场景下挺管用,不然我就掉进了URL复用的坑里。
就这样吧,文章写完,我也该休息了,代码跑了两天一夜,风扇都快转出火星子了,不过最后看到PPT365里完美播放的视频,还是有点意思的。
本文来自作者[kyadmin]投稿,不代表be365立场,如若转载,请注明出处:http://www.uss1.cn/nengyuan/511.html
评论列表(4条)
我是be365的签约作者“kyadmin”!
希望本篇文章《用Golang搞定PPT365抓百度视频,一个程序员的实战笔记》能对你有所帮助!
本站[be365]内容主要涵盖:be365,be365网站,be365网址,ball365体育,Be365排名
本文概览:最近帮朋友做PPT365的素材整理,他非要我从百度视频里扒点东西下来,我一听,这不就是写个爬虫嘛,但说实话,百度视频的反爬机制这两年升级...