说在前面:

下面我们要爬取的是拉钩教育课程上面的视频,课程已经购买过了。但是由于没有提供缓冲和下载视频的功能,所以就打算把视频通过python给下载下来,以下的文章都是参考博友的,自己总结下并学习学习。

正式爬取:

1.拉钩教育的网址:https://kaiwu.lagou.com/,输入自己的账号和密码 ,然后登陆进去,找到自己已经购买的课程(这里我就举这个例子)。

2.通过F12 抓包的方式,进入到控制台的network,最后找到的这个视频的请求地址,同时也找到视频的名字和地址(注意:cookies 和referer 字段 请求的时候一定要带上,因为电脑的原因截图没有显示出来)。

下面是请求头的代码,注意一定要带上cookie 和referer 字段,代码里面的cookie要修改成自己的,要不然会报错。

def __init__(self):self.url = 'https://gate.lagou.com/v1/neirong/kaiwu/getCourseLessons?courseId=131'self.headers = {'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.116 Safari/537.36','Cookie': 'LG_LO7D','Referer': 'https://kaiwu.lagou.com/course/courseInfo.htm?courseId=131','Origin': 'https://kaiwu.lagou.com','Sec-fetch-dest': 'empty','Sec-fetch-mode': 'cors','Sec-fetch-site': 'same-site','x-l-req-header': '{deviceType:1}'}self.queue = Queue()  # 初始化一个队列self.error_queue = Queue()self.save_folder = r"/Users/拉钩视频下载/"

3.分析请求地址和请求后的响应内容,不难发现 返回的数据是json格式,所以只需要使用json()模块解析数据就可以了。
4.现在已经知道请求的地址,然后我们就可以发送请求,再解析数据了。现在有许多的视频网站,都是通过m3u8的方式把视频分割成ts视频流的方式,所以本次我们要得到的就是m3u8文件地址,再通过m3u8文件找到每一个单独的ts视频的地址以及AES128加密的key以及iv偏移量。

具体代码如下:

通过parse_one方法得到了所有课程的m3u8以及课程名,通过字典的形式进行存储,然后把得到的字典传递给下一个方法。

def parse_one(self):""":return:获得所有的课程url和课程名 返回一个队列(请求一次)"""html = requests.get(url=self.url, headers=self.headers).textdit_message = json.loads(html)courseSectionList = dit_message['content']['courseSectionList']for course in courseSectionList:for i in course['courseLessons']:if i['videoMediaDTO'] == None:passelse:fileUrl = i['videoMediaDTO']['fileUrl']theme = i['theme']m3u8_dict = {fileUrl: theme}                # fileUrl就是m3u8视频的url,theme为视频的名字if os.path.exists(os.path.join(self.save_folder, "{}.mp4".format(theme))):print("{}已经存在".format(theme))passelse:self.queue.put(m3u8_dict)  # 将每个本地不存在的视频url(m3u8)和name加入到队列中return self.queue

5.同样的道理,我们还需要向m3u8文件地址发送请求,可以从此请求中获取ts 以及key相关的信息。
然后,从下面这些信息中拿到key(key的url已经找到了,通过requests发送请求即可得到真正的二进制的key )以及所有ts的url(这里ts的url只给出了部分需要自己拼接,用发送请求的url进行拼接)。

这是m3u8文件的内容:

下面是每一节课程下面视频的m3u8地址 和ts地址,可以找一下规律,然后自己拼接下地址:

m3u8地址:
https://1252043158.vod2.myqcloud.com/1d93b969vodtranscq1252043158/097fcc715285890799975988367/drm/v.f240.m3u8
ts地址:
https://1252043158.vod2.myqcloud.com/1d93b969vodtranscq1252043158/097fcc715285890799975988367/drm/v.f240.ts?start=0&end=124655&type=mpegts
https://1252043158.vod2.myqcloud.com/1d93b969vodtranscq1252043158/097fcc715285890799975988367/drm/v.f240.ts?start=124656&end=230319&type=mpegts


这部分代码如下:

def get_key(self, **kwargs):m3u8_dict = kwargsfor m3u8_url in m3u8_dict:                                          # 获取某个视频的urlurl_split = m3u8_url.split('.')[0:-2]str_url = '.'.join(url_split)true_url = str_url.split('/')[0:-1]t_url = '/'.join(true_url)                                      # 拼接ts的url前面部分html = requests.get(url=m3u8_url, headers=self.headers).text    # 请求返回包含ts以及key数据message = html.split('\n')                                      # 获取key以及ts的url# 通过正则表达式获取key的列表以及ts的列表key_parse = re.compile('URI="(.*?)"')key_list = key_parse.findall(html)key = requests.get(url=key_list[0], headers=self.headers).content # 一个m3u8文件中的所有ts对应的key是同一个 发一次请求获得m3u8文件的keyvideo_name = m3u8_dict[m3u8_url]                                  # 视频的名字for i in message:if 'v.f240.ts?' in i:ts_url = t_url + '/' + i                                  # ts_url 就是拼接后每一个ts 视频流地址self.write(key, ts_url, video_name, m3u8_dict)

代码解读:(对响应回来的数据进行各种切割拼接的操作以得到真正有用的内容)

  • 1.遍历上一个请求穿过来的字典,通过这个m3u8_url可以拼接出ts真正的url
  • 2.获取加密的秘钥key
  • 3.将key,ts的url以及课程的名字传递给下一个方法
  • 4.发送请求写入数据

6.破解AES128加密后视频,然后保存到本地,这部分代码如下:

def write(self, key, ts_url, name, m3u8_dict):save_wav = os.path.join(self.save_folder, '{}.mp4'.format(name))cryptor = AES.new(key, AES.MODE_CBC, iv=key)with open(save_wav, 'ab')as f:try:html = requests.get(url=ts_url, headers=self.headers).contentf.write(cryptor.decrypt(html))print('{},{}写入成功'.format(ts_url, name))except Exception as e:print('{}爬取出错'.format(name))while True:if f.close():  # 检查这个出问题的文件是否关闭  闭关则删除然后重新爬取,没关闭则等待10s,直到该文件被删除并重新爬取为止os.remove('{}.mp4'.format(name))print('{}删除成功'.format(name))thread = self.thread_method(self.get_key, m3u8_dict)print("开启线程{},{}重新爬取".format(thread.getName(), name))thread.start()thread.join()breakelse:time.sleep(10)

完整代码如下:

使用多线程threading 和 Queue来爬取,速度提升很多。

import threading
from queue import Queue
import re
import requests
import json
from Crypto.Cipher import AES
import time
import osclass LaGou_spider():def __init__(self):self.url = 'https://gate.lagou.com/v1/neirong/kaiwu/getCourseLessons?courseId=131'self.headers = {'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.116 Safari/537.36','Cookie': 'LG_LOGI-9841821f-45eb-4135-9698-8d6b8280d898; LGUID=20200704113210-6a6a8c61','Referer': 'https://kaiwu.lagou.com/course/courseInfo.htm?courseId=131','Origin': 'https://kaiwu.lagou.com','Sec-fetch-dest': 'empty','Sec-fetch-mode': 'cors','Sec-fetch-site': 'same-site','x-l-req-header': '{deviceType:1}'}self.queue = Queue()  # 初始化一个队列self.error_queue = Queue()self.save_folder = r"/Users/拉钩视频下载"def parse_one(self):""":return:获得所有的课程url和课程名 返回一个队列(请求一次)"""html = requests.get(url=self.url, headers=self.headers).textdit_message = json.loads(html)courseSectionList = dit_message['content']['courseSectionList']for course in courseSectionList:for i in course['courseLessons']:if i['videoMediaDTO'] == None:passelse:fileUrl = i['videoMediaDTO']['fileUrl']theme = i['theme']m3u8_dict = {fileUrl: theme}                # fileUrl就是m3u8视频的url,theme为视频的名字if os.path.exists(os.path.join(self.save_folder, "{}.mp4".format(theme))):print("{}已经存在".format(theme))passelse:self.queue.put(m3u8_dict)  # 将每个本地不存在的视频url(m3u8)和name加入到队列中return self.queuedef get_key(self, **kwargs):m3u8_dict = kwargsfor m3u8_url in m3u8_dict:                                          # 获取某个视频的urlurl_split = m3u8_url.split('.')[0:-2]str_url = '.'.join(url_split)true_url = str_url.split('/')[0:-1]t_url = '/'.join(true_url)                                      # 拼接ts的url前面部分html = requests.get(url=m3u8_url, headers=self.headers).text    # 请求返回包含ts以及key数据message = html.split('\n')                                      # 获取key以及ts的url# 通过正则表达式获取key的列表以及ts的列表key_parse = re.compile('URI="(.*?)"')key_list = key_parse.findall(html)key = requests.get(url=key_list[0], headers=self.headers).content # 一个m3u8文件中的所有ts对应的key是同一个 发一次请求获得m3u8文件的keyvideo_name = m3u8_dict[m3u8_url]                                  # 视频的名字for i in message:if 'v.f240.ts?' in i:ts_url = t_url + '/' + i                                  # ts_url 就是拼接后每一个ts 视频流地址self.write(key, ts_url, video_name, m3u8_dict)def write(self, key, ts_url, name, m3u8_dict):save_wav = os.path.join(self.save_folder, '{}.mp4'.format(name))cryptor = AES.new(key, AES.MODE_CBC, iv=key)with open(save_wav, 'ab')as f:try:html = requests.get(url=ts_url, headers=self.headers).contentf.write(cryptor.decrypt(html))print('{},{}写入成功'.format(ts_url, name))except Exception as e:print('{}爬取出错'.format(name))while True:if f.close():  # 检查这个出问题的文件是否关闭  闭关则删除然后重新爬取,没关闭则等待10s,直到该文件被删除并重新爬取为止os.remove('{}.mp4'.format(name))print('{}删除成功'.format(name))thread = self.thread_method(self.get_key, m3u8_dict)print("开启线程{},{}重新爬取".format(thread.getName(), name))thread.start()thread.join()breakelse:time.sleep(10)# 创建多线程方法def thread_method(self, method, value):thread = threading.Thread(target=method, kwargs=value)return threaddef main(self):global m3u8thread_list = []m3u8_dict = self.parse_one()while not m3u8_dict.empty():for i in range(10):             # 创建10个线程并启动m3u8 = m3u8_dict.get()      # 每次从队列取出一个对象 ,启动一个线程实例化对象,然后再放到线程列表中thread = self.thread_method(self.get_key, m3u8)thread.start()print(thread.getName() + '启动成功,{}'.format(m3u8))time.sleep(1)thread_list.append(thread)for k in thread_list:k.join()  # 回收线程if __name__ == '__main__':run = LaGou_spider()run.main()

其实,我在这里有一个疑问 ,就是那个破解AES加密的时候,为什么iv也是key?
不应该是m3u8文件里面的那个iv偏移量吗?

cryptor = AES.new(key, AES.MODE_CBC, iv=key)

参考博客:Python爬虫实现全自动爬取拉钩教育视频

python 下载拉钩教育AES加密视频相关推荐

  1. Python爬虫实现全自动爬取拉钩教育视频

    ps:改良之后的多线程版本在最后 背景 大饼加了不少技术交流群,之前在群里看到拉钩教育平台在做活动,花了1块钱买了套课程.比较尴尬的是大饼一般都会在上下班的路中学习下(路上时间比较久)而这个视频无法缓 ...

  2. 05_01_拉钩教育课程管理系统之一:项目介绍

    任务一 项目介绍与后台系统搭建 1. 项目架构 1.1 项目介绍 ​ 拉钩教育后台管理系统,是提供给拉钩教育的相关业务人员使用的一个后台管理系统, 业务人员可以在这个后台管理系统中,对课程信息.讲师信 ...

  3. Python突破拉钩反爬机制,采集各类招聘数据

    首先说一下这个有啥用?要说有用也没啥用,要说没用吧,既然能拿到这些数据,拿来做数据分析.能有效的得到职位信息,薪资信息等.也能为找工作更加简单吧,且能够比较有选择性的相匹配的职位及公司 很多人学习py ...

  4. Python selenium 拉钩爬虫

    selenium 用作自动化测试工具,并非爬虫工具,用作爬虫性能没那么好.但既然可以读取网页信息,那还是可以用来爬取数据的.用该工具模拟访问,网站会认为是正常的访问行为. 项目创建几个文件,都在同一个 ...

  5. 使用python下载wallpaper Engine订阅的壁纸/视频

    一.为什么想下载wallpaper Engine的壁纸   在游戏平台steam上,有一个壁纸软件wallpaper Engine,人称小红车,里面有各种好看的动态壁纸和视频,可以给我们的电脑设置动态 ...

  6. python pycrypto_Python使用PyCrypto实现AES加密功能示例

    本文实例讲述了Python使用PyCrypto实现AES加密功能.分享给大家供大家参考,具体如下: #!/usr/bin/env python from Crypto.Cipher import AE ...

  7. 【Python】pyCryptodome模块实现AES加密、解密

    高级加密标准(英语:Advanced Encryption Standard,缩写:AES),在密码学中又称Rijndael加密法,是美国联邦政府采用的一种区块加密标准.这个标准用来替代原先的DES, ...

  8. .net aes加密视频等文件

    公司学习平台在app端下载下来的视频需要加密 随查找资料参考一些写法 写了aes的加密方法 记录防止忘记 using System; using System.Collections.Generic; ...

  9. 一文看懂,python抓取m3u8里ts加密视频及合成、多线程、写入的问题

    花了几天时间搞m3u8里的ts视频,还有多线程协程的处理问题.看了大量的回答,发现大多数人讲的都是个大概,具体的怎么用.什么原理没讲.今天就来带大家讲解怎么爬取m3u8里的加密ts视频. 目标网址我就 ...

最新文章

  1. Android开发之自动登录功能的实现
  2. Springmvc案例1----基于spring2.5的採用xml配置
  3. Android --- 调用MediaStore.Images.Media.insertImage保存图片时生成两张图片的问题
  4. python 3.5.2页面_Python 3.5.2实现websocket服务端
  5. Nginx基本数据结构之ngx_str_t
  6. a5 1c语言实现,初识C语言1_qq5fb3b05a5f322的技术博客_51CTO博客
  7. 如何使用Scylla进行OSINT信息收集
  8. python csv wordpress xmlrpc_wordpress_xmlrpc模块批量自动发布文章到wordpress - 老牛博客...
  9. jpg格式怎么转换成plt格式的_JPEG格式图片转PLT格式雕刻输出
  10. Acrel-2000Z智能电力监控系统解决方案
  11. 量化交易策略代码java_3.量化交易策略基本框架
  12. 30 个 Python 编程实用技巧
  13. c语言 随机四则运算,随机四则运算 C语言
  14. 在 Light Trail Adventures 中探索失落已久的复古未来沙漠城市
  15. 初学Flutter 环境搭建
  16. 台式计算机箱ip5x,IP5X防水是个什么概念?
  17. wap.php区别,WAP與PHP程序設計之基礎篇
  18. MyBatis中的日志(LOG4J)
  19. 完全卸载Myeclipse
  20. 矩阵特征多项式的系数公式

热门文章

  1. abaqus 多层网格绑定_ABAQUS螺栓接触分析
  2. AtomicStampedReference实现
  3. linux cat 进程,Linux下CAT程序的C实现
  4. 在 Linux 操作系统中安装 Java
  5. spark on yarn 配置及异常解决
  6. 第五六周机电传动控制作业
  7. PHP设计模式——享元模式
  8. readSerializableObj
  9. MySQL Cluster 配置详细介绍
  10. router3 BGP1 基础部分