Contents

Datacamp课程资料解析

最近需要频繁的在datacamp上完成课程作业,而datacamp的视频加载特别慢,如果能够将视频打包下载就好了。因此尝试在之前写的go爬虫的基础上增加下载datacamp视频以及字幕的功能。

1.网站分析

1.1 单个视频

单个视频的播放地址示例为

https://projector.datacamp.com/?auto_play=play&projector_key=course_2300_39936ca75b4f429f2edd5a6f5623a0f0&playback_rate=1&quality=auto

这个地址进行get请求可以获得mp4格式视频的地址以及vtt格式字幕的地址,因此每一个视频可以通过该网址进行下载,而拼接出该网址的关键参数为projector_key,接下来的目标就是获得这个参数。

1.2 课程列表

课程页面为

https://learn.datacamp.com/courses/data-visualization-with-ggplot2-2

转换成如下地址

https://campus.datacamp.com/courses/data-visualization-with-ggplot2-2/

发送get请求,在返回的页面中可以获得一个巨大的转义后的json数组

VideoExercise","^1","Stats and Geoms","aggregate_xp",50,"^18",1,"url","https://campus.datacamp.com/courses/data-visualization-with-ggplot2-2/chapter-1-statistics?ex=1

使用正则表达式将其提取出可以获得视频的课程地址,在此地址可以获得视频的projector_key,再拼接出单个视频的播放地址,返回其mp4视频地址以及字幕地址即可。

2. 实现

起始地址示例为

https://campus.datacamp.com/courses/data-visualization-with-ggplot2-2

2.1 获取视频的课程地址

返回视频课程地址的列表

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
func GetDCName(url string)string {
	return utils.MatchAll(url,`courses/(.*)`)[0][1]
}

//从起始地址得到带视频章节的下载页面,返回视频列表
func GetDCStartURLs(starturl string) ([]string) {
	//从起始地址中提取课程名称
	courseName := GetDCName(starturl)
	//拼接出正确的地址
	url := "https://campus.datacamp.com/courses/"+courseName
	data:=utils.HttpGet(url)
	//fmt.Print(data)
	var list []string
	content := utils.MatchAll(data,`VideoExercise.*?(https://campus.datacamp.com/courses/.*?)"`)
	for _,item := range(content){
		list = append(list, item[1])
	}
	return list
}

2.2 返回视频和字幕的下载地址

对于每一个课程地址,用正则表达式提取出projector_key

1
projector_key","course_775_8ef45bdbcab9689af067e6898d1ced76",&quot

拼接出播放地址,发送get请求,返回结果中包含文件信息的内容如下:

{"id":16063,"key":"course_775_8bd0470dcdd674c3f9858a6645528303","video_raw_link":null,"video_mp4_link":"//videos.datacamp.com/transcoded_mp4/775_ggplot2_2/v2/ch1_1.mp4","video_hls_link":"//videos.datacamp.com/transcoded/775_ggplot2_2/v2/hls-ch1_1.master.m3u8","audio_link":"https://s3.amazonaws.com/assets.datacamp.com/production/course_775/audio/chapter1_exercise_3c84aedc95.mp3","slides_link":null,"script_link":"https://assets.datacamp.com/production/course_775/scripts/chapter1_exercise_3c84aedc95.md","subtitle_vtt_link":"https://s3.amazonaws.com/assets.datacamp.com/production/course_775/subtitles/course_775_8bd0470dcdd674c3f9858a6645528303.vtt","transcript_timings":null,"slide_deck_id":null,"created_at":"2018-01-26T20:56:55.000Z","updated_at":"2018-01-26T20:56:55.000Z","deleted_at":null,"thumbnail_link":null,"render_dynamically":0,"dynamic_slide_deck_id":null,"is_projector_video":0,"active_mp4_conversion_id":null,"active_pdf_conversion_id":null}

使用正则表达式提取出这两个地址

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
//提取单个视频的projector_key
func GetPK(url string)(string){
	data:=utils.HttpGet(url)
	PK := utils.MatchAll(data,`projector_key.*?(course_.*?)"`)[0][1]
	return PK
}

//根据project key 返回视频和字幕的下载地址
func GetDCVideo(PK string)(string,string){
	url := "https://projector.datacamp.com/?auto_play=play&projector_key="+PK
	data:=utils.HttpGet(url)
	videoUrl:= "https:"+utils.MatchAll(data,`video_mp4_link.*?(//videos.datacamp.com/transcoded_mp4/.*?mp4)`)[0][1]
	subtitleUrl := utils.MatchAll(data,`subtitle_vtt_link.*?(https.*?vtt)`)[0][1]
	return videoUrl,subtitleUrl
}

2.3 获取课件的下载地址

课件的下载地址列表可以在提取视频课程列表的时候一并完成,修改后的程序如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
//从起始地址得到带视频章节的下载页面,返回视频列表和pdf课件列表
func GetDCStartURLs(starturl string) ([]string,[]string) {
	//从起始地址中提取课程名称
	courseName := GetDCName(starturl)
	//拼接出正确的地址
	url := "https://campus.datacamp.com/courses/"+courseName
	data:=utils.HttpGet(url)
	//fmt.Print(data)
	var urlList []string
	var pdfList []string
	content := utils.MatchAll(data,`VideoExercise.*?(https://campus.datacamp.com/courses/.*?)"`)
	ppts := utils.MatchAll(data,`slides_link.*?(https.*?pdf)`)
	//fmt.Print(ppts)
	for _,item := range(content){
		urlList = append(urlList, item[1])
	}
	//pdfList 有重复的
	for _,item := range(ppts){
		pdfList = append(pdfList, item[1])
	}
	return urlList,pdfList
}

3. 实际运行

由于视频以及课件下载速度比较慢,因此将其下载地址整理到一个文档中,并自动生成批量处理的重命名文件(windows下,linux将ren改为move即可)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
//返回待下载的视频文件列表和字幕文件列表
func ExtractDCVideo(url string)([]utils.File,[]utils.File){
	//需要下载的文件集合
	var videos []utils.File
	var subtitles []utils.File
	urlList,pdfList := GetDCStartURLs(url)
	//放置下载信息的列表
	var  downloadList []string
	var  renameList []string
	//fmt.Println(urlList)
	//对于每一个视频
	for _,item := range(urlList){
		PK := GetPK(item)
		//添加下载链接
		videoUrl,subtitleUrl := GetDCVideo(PK)
		downloadList = append(downloadList,videoUrl )
		downloadList = append(downloadList,subtitleUrl )
		fileName := utils.MatchAll(videoUrl,`.*/(.*?).mp4`)[0][1]
		subtitleName := utils.MatchAll(subtitleUrl,`.*/(.*?.vtt)`)[0][1]
		//添加重命名命令
		renameCM := "ren "+subtitleName+" "+fileName+".vtt"
		fmt.Println(renameCM)
		renameList = append(renameList,renameCM)
		videos = append(videos, utils.File{videoUrl,fileName+".mp4"})
		subtitles = append(subtitles, utils.File{subtitleUrl,fileName+".vtt"})
	}
	utils.WriteFile("downloadList.txt",downloadList)
	utils.WriteFile("rename.bat",renameList)
	utils.WriteFile("pdflist.txt",pdfList)
	return videos,subtitles
}

运行一次生成3个文件

1
go run main.go https://learn.datacamp.com/courses/data-visualization-with-ggplot2-part-3

分别为

  • downloadList.txt 存储视频和字幕地址
  • rename.bat 重命名的批量处理文件
  • pdflist.txt 课件文件

4.总结

该项目的地址为:https://github.com/webscrapingproject/icourse-downloader , 欢迎讨一起讨论!

PS:真的巨久没有更新博客了,接下来希望能够学习一些有趣的机器学习项目(总是在说想做NLP什么的,一直没有动手那就等于没有空想)。自己也要抓紧这时间学习,掌握更多的技术。