wshuo 发表于 2020-5-1 03:18

python实现下载 pp视频(pptv聚力)付费视频(蓝光画质)

源码地址:https://ww.lanzouj.com/ic4v7yd
里面包含了项目源码及ffmpeg,和我写的一个自动安装ffmpeg的脚本并设置环境变量(原理就是通过修改注册表来添加环境变量),运行一下就可以了,可以在cmd 输入ffmpeg测试是否成功(主要是针对windows平台的)

### 前言
前几天我想看一个番剧, 正好搜索到了 PP视频,我才知道PP视频就是PPTV聚力,我想把番剧下载下来,结果发现视频竟然不是m3u8格式,而是多段mp4,所以简单的写了个脚本,可以在不登录的情况下直接下载vip和付费视频蓝光画质(只能说明这个视频网站做的不行)

### 开始分析
经过调试我首先得到了视频地址的url
`https://10314.vcdn.pplive.cn/0/0/1/2de8f8694a79c437a11b09941fb1cb0a.mp4?h5vod.ver=2.1.3&k=0b6a74e50374776203bd05d55a090fba-e800-1588284812&type=mhpptv`

当然,我当时拿到的**url** 是很长的一段还有其他参数,但是我发现那些参数都是无用的影响访问的参数只有这几个
**h5vod.ver : 固定值**
**type : 固定值**
**k : 变值**

说明 k 是一个接口得到的, 所以我需要找到对应的接口就可以了

但是现在还有一个问题就是 这个只是视频的一段, 其他视频分段地址又是什么样的呢?
经过我反复调试发现 url 中的
`https://10314.vcdn.pplive.cn/a/b/c/`
(对应位置我用字母来代替数字了,为了描述方便)
a 为分段视频的第几段
b 默认为0 就可以(具体表示什么不清楚,但是瞎填肯定是不行的)
c 这个数字可以随意瞎填,因为后台解析没用到这个参数,但是要有这个参数
a 为 0 为第一段视频, a 为 1 为第二段视频

所以接下来的问题就是找到那个接口了
经过调试发现了一个接口
`https://web-play.pptv.com/webplay3-0-12407631.xml?o=0&version=6&type=mhpptv&appid=pptv.web.h5&appplt=web&appver=4.0.7&cb=a`
这个接口参数只有一个变量 那就是12407631,也就是id,每一集都有唯一的 id ,而这个id 我们也可以通过访问对应视频播放界面的url后返回的html源码中查看到
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200501023236403.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2Nob3V6aG91OTcwMQ==,size_16,color_FFFFFF,t_70)
返回的不只是一集,而是全剧的每一集id都可以通过一个url来获取到

那么我们来看看 这个接口返回了哪些内容
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200501023604948.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2Nob3V6aG91OTcwMQ==,size_16,color_FFFFFF,t_70)
几种画质的 mp4,知道这些那么我们还查一个 k参数就可以构造视频的url了
经过我查找发现了k值, 一个视频的一种清晰度对应唯一一个k值
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200501023738458.png)
这里用了url编码看起来乱七八糟,用python解码一下

```python
from urllib.parse import unquote
print(unquote("4e6a8848fb388e09708a132bf4caeb4e-5775-1588285899%26bppcataid%3D17"))
```
输出:
```bash
4e6a8848fb388e09708a132bf4caeb4e-5775-1588285899&bppcataid=17
```
可以看到 & 符号前面的就是k ,所以到时候我们可以用& 进行分割然后取 k

到此看起来问题全部解决了我们也可以构造视频url 了,但是还有一个问题, 那就是视频到底分多少段我们还不知道, 毕竟我们不能遍历去访问直到访问不到数据(那样太傻了)

其实接口里面也存在这样的数据了
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200501024452676.png)
画质下面mp4 字段 childNodes 是一个列表,这个列表的长度减1 就是不同画质的分段数, 减1 是因为最后一个元素是别的内容不是描述视频分段信息的, 不得不说这个接口返回的数据构造的真是及其混乱, 我解析的时候都费了很大劲!

到此问题全部解决

### 代码实现
```python
import requests
import re
import json
import os
from threading import Thread
import sys

import time


requests.packages.urllib3.disable_warnings()

def progress():
    width=30
    while True:
      global all_num
      global now_num
      percent = now_num/all_num * 100
      left = int(width * percent // 100)
      right = width - left
      print('\r[', '#' * left, ' ' * right, ']',f' {percent:.0f}%',sep='', end='', flush=True)
      if all_num == now_num:
            break
      time.sleep(1)

def hecheng(sh,path):
    # 判断是否只是一段视频
    if len(os.listdir(path)) <= 2:
      os.remove(path+os.sep+"1.txt")
    else:
      os.system(sh)
      for i in os.listdir(path):
            if i != 'output.mp4':
                os.remove(path+os.sep+i)

def download(url,id_,name):
    global now_num
    data = requests.get(url,headers={"Range": "bytes=0-"},stream=True).content
    with open(name+os.sep+str(id_)+'.mp4','wb') as f:
      f.write(data)
    now_num += 1

def api_get(id_):
    global all_num   
    global now_num
    all_num = 0
    now_num = 0

    api_url = f"https://web-play.pptv.com/webplay3-0-{id_}.xml?o=0&version=6&type=mhpptv&appid=pptv.web.h5&appplt=web&appver=4.0.7&cb=a"
    s = requests.get(api_url,verify=False,headers=headers)
    data = json.loads(s.text)
    try:
      name = data['childNodes']['nm']
    except Exception:
      name = data['childNodes']['nm']
    print("正在下载:"+name)

    rid = data['childNodes'][-4]['rid']
    all_num = len(data['childNodes'][-4]['childNodes']) -1
    kk = data['childNodes'][-5]['childNodes'][-1]['childNodes'].split('%26')
    if not os.path.exists(name):
      os.makedirs(name)


    # 合成命令
    a1 = os.path.abspath(name+os.sep+'1.txt')
    a2 = os.path.abspath(name+os.sep+'output.mp4')
    sh = f'ffmpeg -f concat -safe 0 -i "{a1}" -c copy "{a2}" -loglevel error'
    path = os.path.dirname(a1)

    # 启动进度条线程
    progress_t = Thread(target=progress)
    progress_t.start()

    t_list = []
    t_list.append(progress_t)

    f = open(name+os.sep+'1.txt','w')
    for i in range(all_num):
      video_url = f"https://10314.vcdn.pplive.cn/{i}/0/1/{rid}?h5vod.ver=2.1.3&k={kk}&type=mhpptv"
      f.write("file "+ os.path.abspath(name+os.sep+f'{i}.mp4')+"\n")

      t = Thread(target=download,args=(video_url,i,name))
      t_list.append(t)
      t.start()

      if not mul_t:
            t.join()

    f.close()   
    for t in t_list:
      t.join()
   
    # print(sh)
    print("\n"+name+" 正在合成...")
    hecheng(sh,path)
    print(name+" 合并成功")


def start(url,is_all,s,e,mul_t):
    response = requests.get(url,verify=False,headers=headers)
    if response.status_code == 200:
      result = re.findall("var webcfg = (.*?);",response.text)
      data = json.loads(result)

      if is_all:
      # 下载剧集
            try:
                for item in data['playList']['data']['list']:
                  api_get(item['id'])
            except Exception:
                for item in data['playList']['data']['list']:
                  api_get(item['id'])
      else:
      # 下载单集
            api_get(data['id'])

if __name__ == "__main__":
    all_num = 0
    now_num = 0
    headers = {
      "User-Agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.149 Safari/537.36"
    }

    url = input("输入地址:")
    is_all = input("是否下载全剧(默认否):")
    if is_all:
      r = input("请输入下载剧集(例如1-5,默认全部):")
      if r:
            s,e = r.split("-")   
            s = int(s)
            if e:
                e = int(e)
            else:
                e = None
      else:
            s = None
            e = None

    mul_t = input("是否启用多线程下载(默认否):")
    start(url,is_all,s,e,mul_t)
```

也是做了一个简单的命令行工具,功能有

1. 通过一次输入可以下载全集的蓝光画质视频
2. 下载vip 视频
3. 下载付费视频
4. 下载完分段视频自动调用 ffmpeg 命令进行合成
5. 选择性 下载 m-n集视频
6. 多线程下载(下载电影时候最好不要开启)

使用方法: 视频播放界面的**url**输入进去,然后回车, 剩下的参数不写直接回车相当于`默认`, 随意写什么相当与`是`

其他注意 : windows 使用调用 ffmpeg先要把其加入**系统环境变量**里面,另外 第 81 行代码应改为
```python
f.write("file "+ (os.path.abspath(name+os.sep+f'{i}.mp4')+"\n").replace("\\","\\\\"))
```
这个主要是windows脑残的文件路径问题

TicketForLife 发表于 2020-12-29 18:13

wshuo 发表于 2020-5-2 23:30

那年夏天52 发表于 2020-5-2 16:39
Traceback (most recent call last):
File "C:%users\Administrator\Desktop\pp视频\main.py", line 156 ...

这个说明你输入有问题,在分集下载的时候输入格式为:1-10,然后回车,这样会下载1-10集,如果什么都不输入下载全剧(什么都不输入可以直接回车)

webber.yan 发表于 2020-5-1 03:55

虽然没有看懂,但是感谢楼主的分享,幸苦了

jp84058481 发表于 2020-5-1 06:31

这个支持

tzg2008 发表于 2020-5-1 06:52

非常好的代码!支持一下

psfzq 发表于 2020-5-1 07:01

谢谢分享,就是不明白,好好学习。

老狼客 发表于 2020-5-1 07:06

支持支持,学习就是动力!

Jason68258 发表于 2020-5-1 07:23

谢谢楼主分享

一剑封侯人 发表于 2020-5-1 07:27

楼主可否来个安卓版

xiong779 发表于 2020-5-1 07:55

感谢楼主的分享,幸苦了

Ldfd 发表于 2020-5-1 08:01

you-get不香吗https://i.loli.net/2020/04/17/oF5yZM2pYgnvEDI.png
感谢分享
页: [1] 2 3 4 5 6
查看完整版本: python实现下载 pp视频(pptv聚力)付费视频(蓝光画质)