
使用 python requests 来下载知乎的视频,虽然有更简单的方法。
分析
老规矩,先抓包。
随便进入一个视频页面,进入开发者模式,选择网络,再筛选为 XHR。
很快啊,啪的一下进来,就找到了这么一个请求。

再点开这个 json,发现里面这么些数据:

很明显,这里面有三个不同清晰度的视频,分别是 LD、HD、SD。点开里面的’play_url’之后,就会提示下载一个视频文件。这已经很明显了,这就是我们要找的视频地址。
那要怎么获取呢?
先看下 url,是这样的——(https://lens.zhihu.com/api/v4/videos/1254186650735267840),前面的都是不变的,只有后面ID是动态的。
那么首要任务就是将这个 ID 找出来,在网页代码搜索一下,发现为空。
由于新版的知乎视频里,在答案上插入视频需要将视频发表到另一个地方,所以试着找一下在答案找到这个视频的地址。然后再去访问一下那里,看有没有这个 ID。
很明显,我们在答案的代码中找到了视频的 url 地址,在一个 <script id="js-clientConfig" type="text/json">标签里,有一个整个页面的 json 文件,包括了题目、答案和作者等详细信息,而视频 url 也在里面。
使用正则表达式提取出来,再去访问视频的 url。在视频的网页页面下,搜索一下视频 ID,果然在里面。

所以这就很简单了。
思路
- 先获取答案上的所有的视频 url;
- 再分别访问视频,获取一个返回包含视频信息的 json 的 url;
- 从 json 上获取到真实的视频 url 地址;
- 访问,再保存;
提取 url
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| def get_video_urls(url): res = requests.get(url, headers=headers) answer_id = re.findall(r'answer/(\d+)', url)[0]
text = res.text json_text = re.findall( r'<script id="js-initialData" type="text/json">(.*?)</script>', text)[0]
data = json.loads(json_text) content = data['initialState']['entities']['answers'][answer_id]['content'] video_urls = re.findall(r'(https://www.zhihu.com/zvideo/\d+)', content)
return video_urls
|
获取真实的视频地址以及标题
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| def get_name_url(url): get_video_url = 'https://lens.zhihu.com/api/v4/videos/{}' res = requests.get(url, headers=headers) url = re.findall( '<iframe class="ZVideo-player" src=\"(.*?)\"', res.text)[0] video_id = re.findall(r'/video/(\d+)', url)[0] json_url = get_video_url.format(video_id)
res = requests.get(json_url, headers=headers) data = json.loads(res.text) HD_url = data['playlist']['HD']['play_url']
title = data['title'] video_name = title + '.mp4' return video_name, HD_url
|
保存
1 2 3 4
| def save(name, url): res = requests.get(url, headers=headers) with open(name, 'wb') as fp: fp.write(res.content)
|
完整代码
Github|spider