当前位置:   article > 正文

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

scrapy下载m3u8加密视频

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

目标网址我就不说了,怕被和谐

以《丛林奇航DB》为例吧,首先找到目标网址,再F12检查,点击网络,找到m3u8结尾的链接(找不到的话点击刷新一下)。如下图:

点击预览后会看到一连串的ts链接和以AES-128加密的key链接。如下图:

如果链接不完整的话要手动补全链接。

看到这里的话已经所找到了视频资源,接下来写代码爬取了。

首先导入库:

  1. #!/usr/bin/env python3
  2. # -*- coding: utf-8 -*-
  3. import time
  4. import os
  5. import requests
  6. import re
  7. import aiohttp
  8. import asyncio
  9. from Crypto.Cipher import AES

 crypto库的安装请前往crypto安装 - 百度文库自行了解。

再来说说AES的一个解密ts视频原理,这里以爬取一部ts为例:

  1. from Crypto.Cipher import AES
  2. # 提取key和ts的链接地址进行访问与获取文本
  3. key_url = 'https://pps.shanshanku.com/20211127/g8V4A0hE/1000kb/hls/key.key'
  4. ts_url = 'https://pps.shanshanku.com/20211127/g8V4A0hE/1000kb/hls/z8WfPVdF.ts'
  5. key = requests.get(key_url).content
  6. ts = requests.get(ts_url).content
  7. with open('./date/video.ts', 'wb') as file:
  8. # 用Crupto库里的AES进行解密
  9. crypto = AES.new(key,AES.MODE_CBC, key)
  10. # 解密完成之后就可以写入了
  11. file.write(crypto.decrypt(ts))
  12. file.close()

得到视频。解密成功。没解密直接写入是无法播放的。

 解密原理已经了解,接下来就是如何爬取多个ts视频了。

下面来说说aiohttp库和asyncio库进行协程的用法

  1. # 第一步:得到一个url列表
  2. urls = ['https://baidu.com',
  3. 'https://baidu.com',
  4. 'https://baidu.com']
  5. # 第一步:用asyncio创建一个函数线程,用aiohttp来创建一个支持异步的访问
  6. async def get_status(url):
  7. # 类似session = aiohttp.ClientSession,with 前面要加async,获取东西前用await
  8. async with aiohttp.ClientSession() as session:
  9. async with await session.get(url) as response:
  10. # 如果是<str>类型的就用text().<byte>类型的就用read()
  11. text = await response.text()
  12. return text[:100]
  13. # 第三步:定义一个执行模块
  14. if __name__ == '__main__':
  15. start = time.time()
  16. # 把第一步的列表放入函数块里并导入到tasks列表
  17. tasks = []
  18. for url in urls:
  19. c = get_status(url)
  20. # 把函数块放入线程
  21. task = asyncio.ensure_future(c)
  22. tasks.append(task)
  23. # 循环事件
  24. loop = asyncio.get_event_loop()
  25. loop.run_until_complete(asyncio.wait(tasks))
  26. # 循环完成后进行关闭
  27. loop.close()
  28. print('总耗时:', time.time()-start)

运行后查看三个线程同时启动到完成后的总用时:

我们可以看到,调用线程已经成功,接下来就是怎么获取和写入了:下面对写入进行分析:

  1. ......
  2. # 如果是<str>类型的就用text().<byte>类型的就用read()
  3. text = await response.text()
  4. return text[:100]
  5. # 这里只截取了一小部分
  6. # 增加一个函数块
  7. # 形参规定设为t,对线程运行返回的结果进行接收
  8. def parsel(t):
  9. tlt = t.result()
  10. # 直接打印tlt返回的是一个元组类型,一个线程对应一个元组,这里有三个线程
  11. print(tlt)
  12. # 如果元组里有多个数据时,需要转换为列表才能提取
  13. lis = list(tlt)
  14. with open('./date/http.txt', 'a') as file:
  15. # 对获取的text[:100]进行写入
  16. file.write(str(tlt))
  17. file.close()
  18. ......
  19. c = get_status(url)
  20. # 把函数块放入线程
  21. task = asyncio.ensure_future(c)
  22. # 把parsel函数添加进去。。。。。。。。。。。。。。。。。。。。
  23. task.add_done_callback(parsel)
  24. tasks.append(task)

 我们来看看打印效果和写入效果:

 

到这一步,我们已经知道怎么调用协程和解密包括写入了

假设我们这一步已经提取了所有的ts视频文件

接下来就是对ts视频进行合并与删除源文件了

合并有调用cmd和利用ffmpeg(需要安装):

调用cmd和利用ffmpge进行合成:

  1. # 导入所需模块
  2. import os
  3. # 用ffmpeg进行ts视频合成
  4. cmd = 'ffmpeg -f concat -safe 0 -i complex.txt(合成路径与命名) -c copy output.mp4(输出路径与命名)'
  5. # 调用cmd
  6. os.system(cmd)

这样我们就完成了ts视频的合成。

接下来附上完整的代码

  1. #!/usr/bin/env python3
  2. # -*- coding: utf-8 -*-
  3. # 导入所需的库
  4. import time
  5. import os
  6. import requests
  7. import re
  8. import aiohttp
  9. import asyncio
  10. from Crypto.Cipher import AES
  11. # 创建一个URL列表
  12. m3u8_URL = 'https://pps.sd-play.com/20220424/RN3p7Bj5/1200kb/hls/index.m3u8'
  13. resp = requests.get(url=m3u8_URL).text
  14. # 这里只提取300个ts视频
  15. rst = re.findall('https:(.*?).ts', resp)[:300]
  16. # name = re.findall('1200kb/hls/(.*?).ts',resp)[:5]
  17. # 给文件命名,用列表进行封装
  18. tt = '{}'
  19. names = [tt.format(num) for num in range(10001, 10301)]
  20. # print(rst)
  21. print(names)
  22. # 把ts视频封装进列表里
  23. ts_list = []
  24. for i in rst:
  25. ts_url = 'https:'+i+'.ts'
  26. ts_list.append(ts_url)
  27. # 限制最大协程数用Semaphore,时间原来这里不讲了,不懂再问
  28. concurrency = 15
  29. semaphore = asyncio.Semaphore(concurrency)
  30. # 用asyncio和aiphttp结合创建线程
  31. async def get_request(url, name):
  32. async with semaphore:
  33. # conn = aiohttp.TCPConnector(limit=15)
  34. async with aiohttp.ClientSession() as session:
  35. async with await session.get(url) as response:
  36. # 因为是byte类型,所以用read()
  37. page_text = await response.read()
  38. return page_text, name
  39. def parse(t):
  40. page_text = t.result()
  41. # 返回得到一个元组,转换为列表,再对文件名和内容进行提取
  42. complex = list(page_text)
  43. na = complex[1]
  44. all = complex[0]
  45. # print(na)
  46. # print(all)
  47. # 用crypto里的AES进行解密并保存
  48. key = b'b7d463938dcfabff'
  49. path = 'D:\\thead\\'
  50. with open(f'{path}{na}.ts', 'ab') as file:
  51. cryptor = AES.new(key, AES.MODE_CBC, key)
  52. file.write(cryptor.decrypt(all))
  53. print('下载完成')
  54. if __name__ == '__main__':
  55. start = time.time()
  56. # 定义列表,把元素放进去并开启协程
  57. tasks = []
  58. for url,name in zip(ts_list,names):
  59. c = get_request(url, name)
  60. task = asyncio.ensure_future(c)
  61. task.add_done_callback(parse)
  62. tasks.append(task)
  63. loop = asyncio.get_event_loop()
  64. try:
  65. loop.run_until_complete(asyncio.wait(tasks))
  66. except:
  67. loop.close()
  68. # 为方便ffmpeg合并,这里创建了一个txt文件列表里面包含每个ts的名称。
  69. for j in range(10001, 10301):
  70. with open('D:\\thead\\list.txt', 'a') as file:
  71. file.write(f'file {j}.ts' + '\n')
  72. file.close()
  73. time.sleep(1)
  74. # 调用cmd并利用ffmpeg进行合并
  75. cmd = f'ffmpeg -f concat -safe 0 -i D:\\thead\\list.txt -c copy D:\\thead\\theads\\new01.mp4'
  76. # cmd = f'copy/b D:\\thead\\* D:\\thead\\theads\\new01.ts'
  77. # 合并完成后再调用cmd进行ts文件删除
  78. os.system(cmd)
  79. delete = f'del D:\\thead\\*'
  80. os.system(delete)
  81. # 整个程序运行所需的时间
  82. print('总用时:', time.time()-start)

时间原因,还有些限制协程数就不多说了,有问题可以互相交流学习。

最后看一下效果:

好,大功告成!!!! 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/你好赵伟/article/detail/154665
推荐阅读
相关标签
  

闽ICP备14008679号