1. 1 不可撤销
  2. 2 小年兽 程嘉敏
  3. 3 手放开 李圣杰
  4. 4 迷人的危险3(翻自 dance flow) FAFA
  5. 5 山楂树之恋 程佳佳
  6. 6 summertime cinnamons / evening cinema
  7. 7 不谓侠(Cover 萧忆情Alex) CRITTY
  8. 8 神武醉相思(翻自 优我女团) 双笙
  9. 9 空山新雨后 音阙诗听 / 锦零
  10. 10 Wonderful U (Demo Version) AGA
  11. 11 广寒宫 丸子呦
  12. 12 陪我看日出 回音哥
  13. 13 春夏秋冬的你 王宇良
  14. 14 世界が终わるまでは… WANDS
  15. 15 多想在平庸的生活拥抱你 隔壁老樊
  16. 16 千禧 徐秉龙
  17. 17 我的一个道姑朋友 双笙
  18. 18 大鱼  (Cover 周深) 双笙
  19. 19 霜雪千年(Cover 洛天依 / 乐正绫) 双笙 / 封茗囧菌
  20. 20 云烟成雨(翻自 房东的猫) 周玥
  21. 21 情深深雨濛濛 杨胖雨
  22. 22 Five Hundred Miles Justin Timberlake / Carey Mulligan / Stark Sands
  23. 23 斑马斑马 房东的猫
  24. 24 See You Again Wiz Khalifa / Charlie Puth
  25. 25 Faded Alan Walker / Iselin Solheim
  26. 26 Natural J.Fla
  27. 27 New Soul Vox Angeli
  28. 28 ハレハレヤ(朗朗晴天)(翻自 v flower) 猫瑾
  29. 29 像鱼 王贰浪
  30. 30 Bye Bye Bye Lovestoned
  31. 31 Blame You 眠 / Lopu$
  32. 32 Believer J.Fla
  33. 33 书信 戴羽彤
  34. 34 柴 鱼 の c a l l i n g【已售】 幸子小姐拜托了
  35. 35 夜空中最亮的星(翻自 逃跑计划) 戴羽彤
  36. 36 慢慢喜欢你 LIve版(翻自 莫文蔚) 戴羽彤
  37. 37 病变(翻自 cubi) 戴羽彤
  38. 38 那女孩对我说 (完整版) Uu
  39. 39 绿色 陈雪凝
  40. 40 月牙湾 LIve版(翻自 F.I.R.) 戴羽彤
夜空中最亮的星(翻自 逃跑计划) - 戴羽彤
00:00 / 04:10

夜空中最亮的星 能否听清

那仰望的人 心底的孤独和叹息

夜空中最亮的星 能否记起

那曾与我同行 消失在风里的身影

我祈祷拥有一颗透明的心灵

和会流泪的眼睛

给我再去相信的勇气

越过谎言去拥抱你

每当我找不到存在的意义

每当我迷失在黑夜里

噢喔喔 夜空中最亮的星

请指引我靠近你

夜空中最亮的星 是否知道

那曾与我同行的身影 如今在哪里

夜空中最亮的星 是否在意

是等太阳先升起 还是意外先来临

我宁愿所有痛苦都留在心底

也不愿忘记你的眼睛

哦 给我再去相信的勇气

哦 越过谎言去拥抱你

每当我找不到存在的意义

每当我迷失在黑夜里

噢喔喔 夜空中最亮的星

请照亮我向前行 哒~

我祈祷拥有一颗透明的心灵

和会流泪的眼睛 哦

给我再去相信的勇气

哦 越过谎言去拥抱你

每当我找不到存在的意义

每当我迷失在黑夜里

噢喔喔 夜空中最亮的星

请照亮我向前行

python抓取、解析、下载小电影

前言

一到周末就想搞点有意思的事,比如之前分享的arduino开发,比如上周分享的博客爬虫,今天我又想搞点有意思的事,所以就有了今天的内容——python爬取m3u8视频资源。不过需要在这里需要着重说明的是,技术无罪,切勿用技术搞违法犯罪的事,不然日子真的就越来越有判头了。

知识扩展

在开始抓取m3u8视频之前,我们先了解下m3u8的相关知识,了解的更多,可以让我们少走弯路。

m3u8是什么?

在此之前,我仅仅知道m3u8是一种网络串流,在平时娱乐时候会找一些m3u8的资源,看看直播啥的,直到今天要分享m3u8的相关内容,才真正开始搜集m3u8的相关知识点。关于m3u8连百度百科都没有说明,搜到知乎一篇内容(【全网最全】m3u8到底是什么格式?一篇文章搞定m3u8下载),下面的原理图也是参照的这篇内容:

从上面的原理图中我们可以得到以下知识点:

  • 首先m3u8并非是视频格式,而是视频文件的索引。
  • ts文件才是我们真正播放的视频资源。ts是日本高清摄像机拍摄下进行的封装格式,全称为MPEG2-TSts即"Transport Stream"的缩写。MPEG2-TS格式的特点就是要求从视频流的任一片段开始都是可以独立解码的。

m3u8通常分两种格式,一种是单码率(固定分辨率),一种是多码率(包含多种分别率)。下面就是一个单码率的m3u8文件的内容:

#EXTM3U
#EXT-X-VERSION:3
#EXT-X-TARGETDURATION:10
#EXT-X-MEDIA-SEQUENCE:1619459525
#EXT-X-PROGRAM-DATE-TIME:2021-10-23T05:39:42Z
#EXTINF:10.0,
1634967582-1-1619459525.hls.ts
#EXT-X-PROGRAM-DATE-TIME:2021-10-23T05:39:52Z
#EXTINF:10.0,
1634967592-1-1619459526.hls.ts
#EXT-X-PROGRAM-DATE-TIME:2021-10-23T05:40:02Z
#EXTINF:10.0,
1634967602-1-1619459527.hls.ts

这个就是一个多码率的m3u8文件,从多码率的文件格式可以看出来,多码率中包括了多个单码率是m3u8文链接:

#EXTM3U
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=500000,RESOLUTION=480x270
500kb/hls/index.m3u8
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=300000,RESOLUTION=360x202
300kb/hls/index.m3u8
m3u8文件指令

另外我在另外一篇博客发现m3u8其实是m3u文件的扩展(参考文档2),这可能就是为什么没有找到m3u8相关词条的原因吧,同时在m3u的词条中发现了M#U文件的指令描述(每个字段的含义):

#EXTM3U //必需,表示一个扩展的m3u文件

#EXT-X-VERSION:3 //hls的协议版本号,暗示媒体流的兼容性

#EXT-X-MEDIA-SEQUENCE:xx //首个分段的sequence number

#EXT-X-ALLOW-CACHE:NO //是否缓存

#EXT-X-TARGETDURATION:5 //每个视频分段最大的时长(单位秒)

#EXT-X-DISCONTINUITY //表示换编码

#EXTINF: //每个切片的时长

另外关于m3u的文件指令是有国际标准的,感兴趣的小伙伴可以去看下:

http://tools.ietf.org/html/draft-pantos-http-live-streaming-06

好了,关于m3u8的相关内容,我们就说这么多,感兴趣的小伙伴可以自己继续探索,下面我们看下如何用python抓取、解析和下载m3u8文件索引中的视频文。

抓取、解析、下载

首先我们先要拿到目标视频资源的索引文件,也就是m3u8文件。一般稍微懂点web开发的小伙伴,应该都知道浏览器抓包吧,F12打开浏览器控制台,然后选择Network,刷新下页面,在左侧资源区找到index.m3u8文件。

通常会有两个m3u8,第一个是获取视频码率列表的,也就是多码率m3u8,这个文件我们是没办法直接解析的,我们要找的是包含ts视频资源的m3u8文件。这里我随便在网上搜了一个葫芦娃的视频,然后通过控制台拿到m3u8文件地址:

https://vod1.bdzybf1.com/20200819/wMgIH6RN/1000kb/hls/index.m3u8

下面我们就用python解析下载这个视频文件。

解析m3u8文件

解析m3u8文件最核心的地方是分析m3u8的文件结构,然后根据其文件内容写出对应的解析逻辑。这里我推荐直接用requests库模拟调用,然后分析响应结果,因为用文本工具之类的查看m3u8文件的话,换行符\n、制表符\t这些看起来不够直观,但是requests就不会有这个问题,因为我们解析的就是requests的响应结果。

这里的以我们上面m3u8文件为例响应结果如下:

可以清晰地看出,这个m3u8文件是通过换行符\n分割的,有部分m3u8文件中会出现制表符和换行符组合的情况,所以具体情况具体分析。

另外,我从响应内容中发现,这个视频资源是进行了AES-128加密的,所以后面在下载视频资源的时候要解密。

解析ts视频地址

因为python代码都很简单,代码量也不多,所以就不展开讲了,看代码注释应该可以看懂。这个方法主要是为了获取ts视频文件的地址。

import requests

def getTsFileUrlList(m3u8Url):
    # 组装请求头
    headers = {
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36'
            }
    # 请求 m3u8文件,并拿到文件内容
    ts_rs = requests.get(url = m3u8Url, headers=headers).text
    print(ts_rs)
    # 换行符分割文件内容
    list_content = ts_rs.split('\n');
    print('list_content:{}'.format(list_content))
    player_list = []
    # 循环分割结果
    for line in list_content:
      # 以下拼接方式可能会根据自己的需求进行改动
      if '#EXTINF' in line:
        continue;
      # 仅记录 ts文件地址  
      elif line.endswith('.ts'):
        player_list.append(line)
    print('数据列表组装完成-size: {}'.format(len(player_list)));
    return player_list;

运行上面这个方法的话,最终会获取到m3u8索引文件中所有的ts视频地址,但是由于我们刚才已经从m3u8文件中发现了,视频资源是加密的,所以在下载的时候我们需要解密。

下载文件

这里的方法是下载并解密视频资源,这里我加了一个解密操作,因为注释够清晰,所以我也不过多赘述了

def fileDownloadWithdecrypt(fileSavePath, player_list):
    # 创建文件夹
    if not os.path.exists(fileSavePath):
        os.mkdir(fileSavePath);
    # 循环 ts 视频资源列表
    for index, url in enumerate(player_list):
        # 发送下载请求
        ts_video = requests.get(url = url, headers=headers)
        # 保存文件
        with open('{}/{}.ts'.format(fileSavePath, str(index + 1)), 'wb') as file:
            # 视频资源解密
            context = decrypt(ts_video.content);
            # 文件写入
            file.write(context)
            print('正在写入第{}个文件'.format(index + 1))
    print('下载完成');

下面是解密代码

from Crypto.Cipher import AES   # 用于AES解码

def decrypt(context):
    # 加密的key
    key =  b'2cd1da2aedacaec8';
    # 解密
    cryptor = AES.new(key, AES.MODE_CBC, key);
    decrypt_content = cryptor.decrypt(context);
    return decrypt_content;

这里用的是pycryptodome库,安装方式如下:

 pip3 install pycryptodome

关于密文,在m3u8文件里面已经有了,直接下载就可以拿到,这里我就不通过代码拿了:

这里下载视频会比较费时间,为了提高下效率可以用多线程,但是由于时间的关系就不演示了。

合并视频

合并视频就更简单了,就是讲前面我们保存的视频合并成一个完整的视频,合并完之后的格式是mp4

def fileMerge(filePath):
    # 查询出文件中的ts文件
    c = os.listdir(filePath)
    # 打开视频保存文件
    with open('%s.mp4' % filePath, 'wb+') as f:
      # 循环
      for i in range(len(c)):
        # 打开 ts 视频文件
        x = open('{}/{}.ts'.format(filePath, str(i + 1)), 'rb').read()
        f.write(x)
    print('合并完成')

我看了下,短短的一集葫芦娃,总共被分割成272ts文件(好像比这个多,我没下载完就把网断了):

272ts文件合并成一个视频文件:

好了,到这里我们python爬取m3u8视频资源的实例就结束了,今天的示例还算比较完美,目标也比较完美的达成了。

完整代码如下:

import requests
import os
from Crypto.Cipher import AES   # 用于AES解码

headers = {
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36'
            }

def getTsFileUrlList(m3u8Url):
    ts_rs = requests.get(url = m3u8Url, headers=headers).text
    print(ts_rs)
    list_content = ts_rs.split('\n');
    print('list_content:{}'.format(list_content))
    player_list = []
    index = 1;
    for line in list_content:
      # 以下拼接方式可能会根据自己的需求进行改动
      if '#EXTINF' in line:
        continue;
      elif line.endswith('.ts'):
        player_list.append(line)
    print('数据列表组装完成-size: {}'.format(len(player_list)));
    return player_list;    
    
def fileDownloadWithdecrypt(fileSavePath, player_list):
    if not os.path.exists(fileSavePath):
        os.mkdir(fileSavePath);
    for index, url in enumerate(player_list):
        ts_video = requests.get(url = url, headers=headers)
        with open('{}/{}.ts'.format(fileSavePath, str(index + 1)), 'wb') as file:
            context = decrypt(ts_video.content);
            file.write(context)
            print('正在写入第{}个文件'.format(index + 1))
    print('下载完成');
    
    
def fileMerge(filePath):
    c = os.listdir(filePath)
    with open('%s.mp4' % filePath, 'wb+') as f:
      for i in range(len(c)):
        x = open('{}/{}.ts'.format(filePath, str(i + 1)), 'rb').read()
        f.write(x)
    print('合并完成')
    
    
def decrypt(context):
    key =  b'2cd1da2aedacaec8';
    cryptor = AES.new(key, AES.MODE_CBC, key);
    decrypt_content = cryptor.decrypt(context);
    return decrypt_content;
    
    
if __name__ == '__main__':
    m3u8Url = 'https://vod1.bdzybf1.com/20200819/wMgIH6RN/1000kb/hls/index.m3u8';
    videoList = getTsFileUrlList(m3u8Url);
    print(videoList)
    savePath = "./test"
    fileDownloadWithdecrypt(savePath, videoList);
    fileMerge(savePath);

运行上面的代码,你就可以得到一集完整的葫芦娃
当然,如果你能找到资源,用上面这段代码爬取小电影也是可以的

总结

今天的视频爬虫很简单,可以说非常简单,核心技术点也不多,主要涉及如下几点:

  • request请求
  • 字符串解析(响应结果解析)
  • 文件操作
  • ASE解密

只需要稍微有一点python基础,就可以做出来,所以这里我也没什么好总结的了。

最后,免费为python做一个无偿广告。我一直觉得python是一门不错的语言,特别是作为脚本使用的时候,真的是太方便了,今天它也依然没有让我失望。

其实严格来说,我学python,但是之前一直诟病于它的缩进语法,所以也就一直没入门,直到做了一段时间java web开发之后,回头再看下python,觉得好简单,于是就又愉快地使用它了,不过用它写脚本真的太爽了,短短几行代码,搞定java一个繁琐的项目,而且用起来也很轻便。

最近一年多的时间,我用它处理过数据、用它跑数据库统计过数据,然后日程工作中我可以用它生成文件目录、爬取资料,也感觉我对它越来越有好感,所以在这里强烈安利各位小伙伴都来学下python,特别是那些非开发岗位的小伙伴,python简直是统计数据的利器,虽然不像广告吹的那么秀,但是技多不压身呀,而且它真的是可以极大提供我们的效率。

最后的最后,再强调下,技术无罪,切勿用技术搞违法犯罪的事,不然日子真的就越来越有判头了!

技术无罪,切勿用技术搞违法犯罪的事,不然日子真的就越来越有判头了!

技术无罪,切勿用技术搞违法犯罪的事,不然日子真的就越来越有判头了!

重要的事情说三遍!!!

另外,今天忙着搞爬虫了,设计模式的类图还没来得及补,明天要加下油了。好了,铁子们,晚安吧

参考内容
posted @ 2021-10-23 22:34  云中志  阅读(802)  评论(0编辑  收藏  举报