极客时间爬虫分析

656 阅读9分钟

核心概要


笔者是一名无缘211、985名校的大专生。虽为大专生但我的人生格言 “别向这个世界认输 因为你还有个牛逼的梦想” 不允许我只是一名普普通通的大专生。

年关已过 恢复正轨

笔者为了提升自身技术实力在 极客时间 用了一些银子买了门课程,但是没想到的是马上就要开学了,而 极客时间 的视频也只能在APP 内部缓存下载观看,很显然这个规则束缚了笔者。作为未来互联网的开发人员面对这种束缚当然是不能妥协的,于是就有了本专刊,本文章。

敢想敢做 不悔青春

下面我会以一名小白的角度来描述此次爬虫分析,当然了 笔者也是一名小白但只是比小白略强那么一些而已。





目标分析


VX: ZhangchongSR0208

VX: ZhangchongSR0208





爬虫分析


账户中心

POST account.geekbang.org/account/use…

  1. 点击个人头像中的 用户名 会触发此接口的调用
  2. 通过分析此接口可以知道 极客时间 是以什么方案来解决 前端与后端交互安全认证的问题
  3. 当然有的小伙伴会想到使用Session 来解决此问题,但是却忽略了Session 这个东西是存储在服务端的,而客户端存储的是SessionId 当浏览器关闭的时候这个SessionId 就会消失,而存储在服务端的Session 还会存在,这无疑是增加了服务端的压力,虽然在服务端做一些Session 的失效策略,但抛去这个问题不说,像这种大型的互联网项目服务端必然会是以集群的方式存在的,这个时候就需要考虑到Session 的共享问题或者是Session 的绑定问题等等。
  4. 使用Cookie Token 解决此问题,Cookie Token 是只存储在客户端的文件,这相比于Session 来说是比较好的一种选择,因为这个时候服务端只需要考虑怎么解析和生成Cookie Token 就可以了,而不需要考虑像Session 的共享问题等等。当然这也是 大型互联网项目中前后端交互安全认证问题解决方案中一种业界主流的解决方案
  5. 通过分析这个接口的RequestHeaders 中可以发现,它采用的是Cookie 来封装一些 认证信息。当然了有懂Cookie 的小伙伴就有想法了,但是你要知道笔者也不是憨憨 ,所以这里的Cookie 肯定是过期的了。
	Accept: application/json, text/plain, */*
	Accept-Encoding: gzip, deflate, br
	Accept-Language: zh-CN,zh;q=0.9
	Connection: keep-alive
	Content-Length: 2
	Content-Type: application/json
	Cookie: _ga=GA1.2.1045223782.1639395871; LF_ID=1639395871969-5650567-1016048; GCID=5a7e11c-5fdc6e0-ec86384-1cc8de6; GRID=5a7e11c-5fdc6e0-ec86384-1cc8de6; MEIQIA_TRACK_ID=24ixuWXpI5WXM68hM1n4NdW4IrF; _gcl_au=1.1.2051684781.1644253524; _gid=GA1.2.302668339.1645078454; MEIQIA_VISIT_ID=25EJkkTDspp5EBAfgoPEKy7mcbm; GCESS=BgsCBgAEBAAvDQAKBAAAAAAGBPiLPOANAQEMAQEDBBwlDmIHBC7OZx8JAQEBCDVaLAAAAAAAAgQcJQ5iBQQAAAAACAED; sensorsdata2015jssdkcross=%7B%22distinct_id%22%3A%222906677%22%2C%22first_id%22%3A%2217f073deb255c7-09d380380dbee5-f791539-1327104-17f073deb261016%22%2C%22props%22%3A%7B%22%24latest_traffic_source_type%22%3A%22%E7%9B%B4%E6%8E%A5%E6%B5%81%E9%87%8F%22%2C%22%24latest_search_keyword%22%3A%22%E6%9C%AA%E5%8F%96%E5%88%B0%E5%80%BC_%E7%9B%B4%E6%8E%A5%E6%89%93%E5%BC%80%22%2C%22%24latest_referrer%22%3A%22%22%2C%22%24latest_landing_page%22%3A%22https%3A%2F%2Ftime.geekbang.org%2F%22%2C%22%24latest_utm_source%22%3A%22time_web%22%2C%22%24latest_utm_medium%22%3A%22menu%22%2C%22%24latest_utm_campaign%22%3A%22timewebmenu%22%2C%22%24latest_utm_content%22%3A%22menu%22%2C%22%24latest_utm_term%22%3A%22timewebmenu%22%7D%2C%22%24device_id%22%3A%2217db39bc70f775-0956fde004162-4343363-2073600-17db39bc710104d%22%7D; Hm_lvt_59c4ff31a9ee6263811b23eb921a5083=1645080295,1645094172,1645096912,1645164399; gksskpitn=13b506d9-98e1-440a-8777-1641eb71065d; _gat=1; Hm_lpvt_59c4ff31a9ee6263811b23eb921a5083=1645164463; SERVERID=1fa1f330efedec1559b3abbcb6e30f50|1645164465|1645164401; gk_process_ev={%22count%22:7%2C%22target%22:%22%22%2C%22utime%22:1645164473299}
	Host: account.geekbang.org
	Origin: https://account.geekbang.org
	Referer: https://account.geekbang.org/dashboard/info
	sec-ch-ua: " Not;A Brand";v="99", "Google Chrome";v="97", "Chromium";v="97"
	sec-ch-ua-mobile: ?0
	sec-ch-ua-platform: "Windows"
	Sec-Fetch-Dest: empty
	Sec-Fetch-Mode: cors
	Sec-Fetch-Site: same-origin
	User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.99 Safari/537.36

我的课程

POST time.geekbang.org/serv/v3/lea…

  1. 点击个人头像中的 我的课程 会触发此接口的调用
  2. Request Body
    • desc 是否排序
    • expice 失效枚举
    • last_learn 最后一次学习
    • learn_status 用户身份
    • prev 当前页码
    • size 分页大小
	{
		"desc": true,
		"expire": 1,
		"last_learn": 0,
		"learn_status": 0,
		"prev": 0,
		"size": 20,
		"sort": 1,
		"type": "",
		"with_learn_count": 1
	}
  1. Response Body
    • code 响应状态码
    • data 数据信息
      • list 课程的重要参数 pid 课程ID
      • articles 这个应该是专刊信息或者是文档信息
      • products 所有课程信息
    • error 错误信息
{
	"code": 0,
	"data": {
		"has_expiring_product": false,
		"learn_count": {
			"total": 1
		},
		"list": [{
			"pid": 739995653,
			"ptype": "p35",
			"aid": 0,
			"ctime": 739995653,
			"score": 2,
			"is_expire": false,
			"expire_time": 0,
			"last_learned_time": 0
		}],
		"articles": [{...}],
		"products": [{...}],
		"page": {
			"more": false,
			"count": 0,
			"score": 0,
			"score0": 0
		}
	},
	"error": {},
	"extra": {
		"cost": 739995653,
		"request-id": "739995653"
	}
}
  1. 请求此接口的时候是需要携带CookieReferer 等请求头参数。
  2. 分析此接口,别的不说 但 ResponseBody 中的list 集合中的 pid 属性肯定是能帮助笔者达到目的。
  3. 虽然里面有一些数据可以用到,但是这还不够详细,继续往下分析。

课程详情

POST time.geekbang.org/serv/v1/col…

  1. 点击我的课程中的 具体课程 会触发此接口的调用
  2. Request Body
    • cid 课程ID
    • size 显示多少课程列表条数
    • prev 当前页码
    • order 排序规则
	{
		"cid": "739995653",
		"size": 500,
		"prev": 0,
		"order": "earliest",
		"sample": false
	}
  1. Response Body
    • error 错误信息
    • data
      • list 课程列表信息 其中的id 是非常重要的,用来获取视频信息的
      • page 分页数据
	{
		"error": [],
		"data": {
			"list": [{
				"article_subtitle": "",
				"video_cover": "...",
				"id": 739995653,
				"had_viewed": true,
				"article_title": "張冲: 别向这个世界认输 因为你还有个牛逼的梦想",
				"article_cover": "",
				"video_media_map": {
					"sd": {
						"size": 739995653
					},
					"ld": {
						"size": 739995653
					},
					"hd": {
						"size": 739995653
					}
				},
				"is_video_preview": true,
				"article_summary": "張冲: 别向这个世界认输 因为你还有个牛逼的梦想",
				"column_had_sub": true,
				"is_finished": false,
				"subtitles": [],
				"include_audio": false,
				"article_could_preview": false,
				"chapter_id": "2457",
				"rate_percent": 1,
				"video_size": 739995653,
				"video_time_arr": {
					"m": "55",
					"s": "40",
					"h": "00"
				},
				"video_id": "VX: ZhangchongSR0208",
				"column_sku": 739995653,
				"offline": {
					"file_name": "",
					"download_url": ""
				},
				"video_time": "00:00:00",
				"is_required": true,
				"rate": {...},
				"score": 739995653,
				"article_ctime": 739995653
			}, {...}],
			"page": {
				"count": 739995653,
				"more": false
			}
		},
		"code": 0
	}
  1. 请求此接口的时候是需要携带CookieReferer 等请求头参数。
  2. 分析此接口,别的不说 但 ResponseBody 中的 list 集合中的 id 属性肯定是能帮助笔者达到目的。
  3. 虽然里面有一些数据可以用到,但是这还不够详细,继续往下分析。.

观看视频

POST time.geekbang.org/serv/v1/art…

  1. 观看 具体课程的视频 会触发此接口的调用
  2. Request Body
    • id 课程列表的ID
	{
		"id": 739995653
	}
  1. Response Body
    • article_content 列表详情
    • article_title 列表标题
    • video_id 视频ID
    • video_cover 视频封面
    • product_id 课程ID
    • id 列表ID
    • hls_videos HLS 视频播放地址
      • ld 标清
      • sd 高清
      • hd 超清
	{
		"data": {
			"article_content": "張冲: 别向这个世界认输 因为你还有个牛逼的梦想",
			"article_title": "張冲: 别向这个世界认输 因为你还有个牛逼的梦想",
			"video_id": "739995653",
			"video_cover": "...",
			"product_id": 739995653,
			"id": 739995653,
			"hls_videos": {
				"sd": {
					"url": "...?combat.m3u8",
					"size": 739995653
				},
				"hd": {
					"url": "...?combat.m3u8",
					"size": 739995653
				},
				"ld": {
					"url": "...?combat.m3u8",
					"size": 739995653
				}
			},
		}
	}
  1. 请求此接口的时候是需要携带CookieReferer 等请求头参数。
  2. 分析此接口,最终我们得到了视频的地址,因为视频采用的是HLS 协议的形式,因为小编的技术还没有发展到全栈开发,所以对这个东西了解的不是很深,只知道使用HLS 的方式会增加视频播放的流畅度,同时还可以根据网络情况来动态切换清晰度,所以它hls_videos 里面有三个清晰度可以选用。

虽然拿到了M3U8 文件,但是真的可以下载吗?

  1. 下面只是M3U8 文件的一部分,我们来看一下。
  2. 这个文件的地址是存储在hls_videos 里面的,通常HLS 这个协议所携带的数据都是加密的
  3. 在看M3U8 文件头中的EXT-X-KEY 属性,它所采用的加密算法是AES-128
  4. 虽然它加密了,但M3U8 文件中也会有对应的解密文件,也就是 URIVI 这两个属性。
  5. 现在市面上也有一些M3U8 下载器解析器,开源社区也有一些M3U8 下载器解析器,这里就不过多解释了。
  6. 温馨提示极客时间 播放视频所用的M3U8 文件并不是我在上面所拿到的文件,它使用到了阿里云的HLS 服务(阿里云里面可以设置,使用标准的HLS 加密或者使用阿里云私有加密),很不幸的是 极客时间 使用的是阿里云私有加密。所以如果直接对 极客时间 播放视频所用的M3U8 文件进行解析或下载的话,得到的视频是不能直接观看的。
#EXTM3U
#EXT-X-VERSION:3
#EXT-X-ALLOW-CACHE:YES
#EXT-X-TARGETDURATION:10
#EXT-X-MEDIA-SEQUENCE:0
#EXT-X-KEY:METHOD=AES-128,URI="...?combat.key",VI=0x00000000000000000000000000000000
#EXTINF:10.000000,
413092fce65236f43dcb599457923728-sd-encrypt-stream-00001.ts
#EXTINF:10.000000,
413092fce65236f43dcb599457923728-sd-encrypt-stream-00002.ts
#EXTINF:10.000000,
413092fce65236f43dcb599457923728-sd-encrypt-stream-00003.ts
#EXTINF:10.000000,
413092fce65236f43dcb599457923728-sd-encrypt-stream-00004.ts




笔者留言


  • 上面所展示的一些数据都不是真实的数据
  • 以上是小编对极客时间爬虫分析的所有分享
  • 注意: 爬虫要有度 从入门到放弃 人生不易要及时放弃
  • 最后: 别向这个世界认输 因为你还有个牛逼的梦想

VX ZhangchongSR0208


技术交流群 577729045 (快来和小编一起探讨交流吧)

以上内容如有冒犯 今致歉谢 恳望见原 请联系小编进行删除