经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 程序设计 » Python3 » 查看文章
python3.6根据m3u8下载mp4视频
来源:jb51  时间:2019/6/18 8:35:44  对本文有异议

需要下载某网站的视频,chrome浏览器按F12打开开发者模式,发现视频链接是以"blob:http"开头的链接,打开这个链接后找不到网页,网上查了下,找到了下载方法,在这里做个记录,如果有错误,欢迎指出。

程序在Windows 10下运行,不过Linux应该也没问题。

使用到的有re模块,requests模块和Crypto模块,其中requests模块和Crypto模块如果没安装可以使用pip命令安装。(Crypto模块安装感觉比较坑,我是从anaconda里拷贝了一份)

下面开始正题:

注:以下使用的m3u8文件所在的网站是自己搭建用来测试的,链接可能会失效。

首先在chrome的network里找到一个m3u8文件的请求,可以通过它下载视频。

通过Preview可以看到m3u8文件的内容。

这里m3u8文件比较重要的内容有两个。

一个是URI后面的链接,这个是加密和解密的秘钥,如果m3u8文件里有这个URI,那么这个视频就是经过了加密的,加密的方法可以看URI前面,这里是AES-128加密算法。

另一个是以ts结尾链接,这个是视频片段,如果是没进行加密的,可以直接打开这个链接下载视频片段,下载下来的是后缀为ts的文件,一般可以直接播放,不过时间很短。如果是加密过的,下载后播放会提示视频文件已损坏。

知道这些后,就可以进行下载了,先获取m3u8文件的内容,然后解析出秘钥(key)和ts的链接,然后下载key对每一个ts进行解密,保存到一个mp4文件里。

下载用的是requests模块,解析key和ts的链接是用的re模块,解密用的是Crypto模块。

使用Crypto需要注意三个地方,一个是安装和导入,第二个是Crypto里AES.new的参数,第三个是decrypt方法的参数。下面先看代码。

导入模块:

  1. import re
  2. import requests
  3. from Crypto.Cipher import AES

初始设置:

  1. # 保存的mp4文件名
  2. name = "dream_it_possible.mp4"
  3.  
  4. # m3u8文件的url
  5. url = "http://www.jiuyi.info/static/video/secret/dream_it_possible.m3u8"
  6.  
  7.  
  8. # 请求头,不一定需要,看网站更改
  9. headers = {
  10. "Referer": "http://www.jiuyi.info/video/dream_it_possible",
  11. "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 "
  12. "(KHTML, like Gecko) Chrome/71.0.3578.80 Safari/537.36",
  13. }

获取m3u8文件内容,并解析出key和ts文件的url。

  1. # 获取m3u8文件内容
  2. r = requests.get(url)
  3.  
  4. # 通过正值表达式获取key和ts的url
  5. k = re.compile(r"http://.*?\.key") # key的正则匹配
  6. t = re.compile(r"http://.*?\.ts") # ts的正则匹配
  7. key_url = k.findall(r.text)[0] # key的url
  8. ts_urls = t.findall(r.text) # ts的url列表

下载并解密ts文件,保存为mp4文件。

  1. # 下载key
  2. key = requests.get(key_url).content
  3.  
  4. # 解密并保存ts
  5. for ts_url in ts_urls:
  6.  
  7. ts_name = ts_url.split("/")[-1] # ts文件名
  8.  
  9. # 解密,new有三个参数,
  10. # 第一个是秘钥(key)的二进制数据,
  11. # 第二个使用下面这个就好
  12. # 第三个IV在m3u8文件里URI后面会给出,如果没有,可以尝试把秘钥(key)赋值给IV
  13. sprytor = AES.new(key, AES.MODE_CBC, IV=key)
  14.  
  15. # 获取ts文件二进制数据
  16. ts = requests.get(ts_url).content
  17.  
  18. # 密文长度不为16的倍数,则添加二进制"0"直到长度为16的倍数
  19. while len(ts) % 16 != 0:
  20. ts += b"0"
  21. # 写入mp4文件
  22. with open(name, "ab") as file:
  23. # decrypt方法的参数需要为16的倍数,如果不是,需要在后面补二进制"0"
  24. file.write(sprytor.decrypt(ts))
  25. print(name, "下载完成")

到这里就下载完成了。

完整代码:

  1. import re
  2. import requests
  3. from Crypto.Cipher import AES
  4.  
  5.  
  6. # 保存的mp4文件名
  7. name = "dream_it_possible.mp4"
  8.  
  9. # m3u8文件的url
  10. url = "http://www.jiuyi.info/static/video/secret/dream_it_possible.m3u8"
  11.  
  12.  
  13. # 请求头,不一定需要,看网站更改
  14. headers = {
  15. "Referer": "http://www.jiuyi.info/video/dream_it_possible",
  16. "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 "
  17. "(KHTML, like Gecko) Chrome/71.0.3578.80 Safari/537.36",
  18. }
  19.  
  20. print("正在解析:" + url.split("/")[-1])
  21.  
  22. # 获取m3u8文件内容
  23. r = requests.get(url)
  24.  
  25. # 通过正值表达式获取key和ts的链接
  26. k = re.compile(r"http://.*?\.key") # key的正则匹配
  27. t = re.compile(r"http://.*?\.ts") # ts的正则匹配
  28. key_url = k.findall(r.text)[0] # key的url
  29. ts_urls = t.findall(r.text) # ts的url列表
  30.  
  31. # 下载key的二进制数据
  32. print("正在下载key")
  33. key = requests.get(key_url).content
  34.  
  35. # 解密并保存ts
  36. for ts_url in ts_urls:
  37.  
  38. ts_name = ts_url.split("/")[-1] # ts文件名
  39.  
  40. # 解密,new有三个参数,
  41. # 第一个是秘钥(key)的二进制数据,
  42. # 第二个使用下面这个就好
  43. # 第三个IV在m3u8文件里URI后面会给出,如果没有,可以尝试把秘钥(key)赋值给IV
  44. sprytor = AES.new(key, AES.MODE_CBC, IV=key)
  45.  
  46. # 获取ts文件二进制数据
  47. print("正在下载:" + ts_name)
  48. ts = requests.get(ts_url).content
  49.  
  50. # 密文长度不为16的倍数,则添加b"0"直到长度为16的倍数
  51. while len(ts) % 16 != 0:
  52. ts += b"0"
  53.  
  54. print("正在解密:" + ts_name)
  55.  
  56. # 写入mp4文件
  57. with open(name, "ab") as file:
  58. # # decrypt方法的参数需要为16的倍数,如果不是,需要在后面补二进制"0"
  59. file.write(sprytor.decrypt(ts))
  60. print("保存成功:" + ts_name)
  61. print(name, "下载完成")

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持w3xue。

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号