用 python 抓取知乎指定回答下的视频

原创
2018/11/06 20:03
阅读数 0

前言

现在知乎允许上传视频,奈何不能下载视频,好气哦,无奈之下研究一下了,然后撸了代码,方便下载视频保存。

接下来以 https://www.zhihu.com/question/268021660/answer/520507373 回答为例,分享一下整个下载过程。

调试一下

打开 F12, 找到光标,如下图:

然后将光标移动到视频上。如下图:

咦这是什么?视野中出现了一条神秘的链接: https://www.zhihu.com/video/xxxxx,让我们将这条链接复制到浏览器上,然后打开:

似乎这就是我们要找的视频,不要着急,让我们看一看,网页的请求,然后你会发现一个很有意思的请求(重点来了):

让我们自己看一下数据吧:

  
    
  
  
  1. {

  2.    "playlist": {

  3.        "ld": {

  4.            "width": 360,

  5.            "format": "mp4",

  6.            "play_url": "https://vdn.vzuu.com/LD/05fc411e-d8e0-11e8-bb8b-0242ac112a0b.mp4?auth_key=1541477643-0-0-987c2c504d14ab1165ce2ed47759d927&expiration=1541477643&disable_local_cache=1",

  7.            "duration": 17,

  8.            "size": 1123111,

  9.            "bitrate": 509,

  10.            "height": 640

  11.        },

  12.        "hd": {

  13.            "width": 720,

  14.            "format": "mp4",

  15.            "play_url": "https://vdn.vzuu.com/HD/05fc411e-d8e0-11e8-bb8b-0242ac112a0b.mp4?auth_key=1541477643-0-0-8b8024a22a62f097ca31b8b06b7233a1&expiration=1541477643&disable_local_cache=1",

  16.            "duration": 17,

  17.            "size": 4354364,

  18.            "bitrate": 1974,

  19.            "height": 1280

  20.        },

  21.        "sd": {

  22.            "width": 480,

  23.            "format": "mp4",

  24.            "play_url": "https://vdn.vzuu.com/SD/05fc411e-d8e0-11e8-bb8b-0242ac112a0b.mp4?auth_key=1541477643-0-0-5948c2562d817218c9a9fc41abad1df8&expiration=1541477643&disable_local_cache=1",

  25.            "duration": 17,

  26.            "size": 1920976,

  27.            "bitrate": 871,

  28.            "height": 848

  29.        }

  30.    },

  31.    "title": "",

  32.    "duration": 17,

  33.    "cover_info": {

  34.        "width": 720,

  35.        "thumbnail": "https://pic2.zhimg.com/80/v2-97b9435a0c32d01c7c931bd00120327d_b.jpg",

  36.        "height": 1280

  37.    },

  38.    "type": "video",

  39.    "id": "1039146361396174848",

  40.    "misc_info": {}

  41. }

没错了,我们要下载的视频就在这里面,其中 ld 代表普清,sd 代表标清, hd 代表高清,把相应链接再次在浏览器打开,然后右键保存就可以下载视频了。

代码

知道整个流程是什么样子,接下来撸代码的过程就简单了,这里就不过再做过多解释了,直接上代码:

  
    
  
  
  1. # -*- encoding: utf-8 -*-

  2. import re

  3. import requests

  4. import uuid

  5. import datetime

  6. class DownloadVideo:

  7.    __slots__ = [

  8.        'url', 'video_name', 'url_format', 'download_url', 'video_number',

  9.        'video_api', 'clarity_list', 'clarity'

  10.    ]

  11.    def __init__(self, url, clarity='ld', video_name=None):

  12.        self.url = url

  13.        self.video_name = video_name

  14.        self.url_format = "https://www.zhihu.com/question/\d+/answer/\d+"

  15.        self.clarity = clarity

  16.        self.clarity_list = ['ld', 'sd', 'hd']

  17.        self.video_api = 'https://lens.zhihu.com/api/videos'

  18.    def check_url_format(self):

  19.        pattern = re.compile(self.url_format)

  20.        matches = re.match(pattern, self.url)

  21.        if matches is None:

  22.            raise ValueError(

  23.                "链接格式应符合:https://www.zhihu.com/question/{number}/answer/{number}"

  24.            )

  25.        return True

  26.    def get_video_number(self):

  27.        try:

  28.            headers = {

  29.                'User-Agent':

  30.                'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36'

  31.            }

  32.            response = requests.get(self.url, headers=headers)

  33.            response.encoding = 'utf-8'

  34.            html = response.text

  35.            video_ids = re.findall(r'data-lens-id="(\d+)"', html)

  36.            if video_ids:

  37.                video_id_list = list(set([video_id for video_id in video_ids]))

  38.                self.video_number = video_id_list[0]

  39.                return self

  40.            raise ValueError("获取视频编号异常:{}".format(self.url))

  41.        except Exception as e:

  42.            raise Exception(e)

  43.    def get_video_url_by_number(self):

  44.        url = "{}/{}".format(self.video_api, self.video_number)

  45.        headers = {}

  46.        headers['Referer'] = 'https://v.vzuu.com/video/{}'.format(

  47.            self.video_number)

  48.        headers['Origin'] = 'https://v.vzuu.com'

  49.        headers[

  50.            'User-Agent'] = 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.67 Safari/537.36'

  51.        headers['Content-Type'] = 'application/json'

  52.        try:

  53.            response = requests.get(url, headers=headers)

  54.            response_dict = response.json()

  55.            if self.clarity in response_dict['playlist']:

  56.                self.download_url = response_dict['playlist'][

  57.                    self.clarity]['play_url']

  58.            else:

  59.                for clarity in self.clarity_list:

  60.                    if clarity in response_dict['playlist']:

  61.                        self.download_url = response_dict['playlist'][

  62.                            self.clarity]['play_url']

  63.                        break

  64.            return self

  65.        except Exception as e:

  66.            raise Exception(e)

  67.    def get_video_by_video_url(self):

  68.        response = requests.get(self.download_url)

  69.        datetime_str = datetime.datetime.now().strftime("%Y-%m-%d %H-%M-%S")

  70.        if self.video_name is not None:

  71.            video_name = "{}-{}.mp4".format(self.video_name, datetime_str)

  72.        else:

  73.            video_name = "{}-{}.mp4".format(str(uuid.uuid1()), datetime_str)

  74.        path = "{}".format(video_name)

  75.        with open(path, 'wb') as f:

  76.            f.write(response.content)

  77.    def download_video(self):

  78.        if self.clarity not in self.clarity_list:

  79.            raise ValueError("清晰度参数异常,仅支持:ld(普清),sd(标清),hd(高清)")

  80.        if self.check_url_format():

  81.            return self.get_video_number().get_video_url_by_number().get_video_by_video_url()

  82. if __name__ == '__main__':

  83.    a = DownloadVideo('https://www.zhihu.com/question/53031925/answer/524158069')

  84.    print(a.download_video())

结语

代码还有优化空间,这里面我只是下载了回答中的第一个视频,理论上应该存在一个回答下可以有多个视频的。如果还有什么疑问或者建议,可以多多交流。点击查看原文查看源代码


本文分享自微信公众号 - 桃子的学习笔记(LeeTaoThinks)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

展开阅读全文
打赏
0
0 收藏
分享
加载中
更多评论
打赏
0 评论
0 收藏
0
分享
返回顶部
顶部