一款超好用的Python油管视频下载工具
阅读本文大概需要 3 分钟。
在这里介绍一个工具,使用它我们可以非常方便地使用 Python 下载 Youtube 的视频,叫做 pytube。
利用它我们可以实现如下功能:
支持 progresive 和 DASH 视频流的下载 支持下载完整的播放列表 可以处理下载进行中和下载完成的回调 提供命令行直接执行下载 支持下载字幕 支持将字幕输出为 srt 格式 获取视频缩略图
下面我们就来详细了解一下它的使用方法。
安装
首先看下安装过程,安装非常简单,只需要使用 pip3 安装即可,命令如下:
pip3 install pytube
或者直接源码安装也行:
pip3 install git+https://github.com/pytube/pytube
安装完成之后就可以使用 pytube 命令了。
使用
这里先介绍两个最常见的用法,那就是直接使用 pytube 命令,它可以用来下载单个 Yotube 视频或者视频列表。
比如这是一个视频 https://youtube.com/watch?v=2lAe1cqCOXo,截图如下:
我们可以直接使用命令下载:
pytube https://www.youtube.com/watch?v=2lAe1cqCOXo
很快视频就能被下载下来了:
Loading video...
YouTube Rewind 2019 For the Record YouTubeRewind.mp4 | 83 MB
↳ |█████████ | 21.4%
同样地,pytube 还能下载播放列表,比如这是一个播放列表 https://www.youtube.com/playlist?list=PLS1QulWo1RIaJECMeUT4LFwJ-ghgoSH6n,截图如下:
使用 pytube 同样可以轻松下载:
pytube https://www.youtube.com/playlist?list=PLS1QulWo1RIaJECMeUT4LFwJ-ghgoSH6n
它可以解析播放列表,然后一个个下载下来:
Loading playlist...
Python Tutorial for Beginners 1 - Getting Started and Installing Python (For Absolute Beginners).mp4 | 63 MB
↳ |████████████████████████████████████████████| 100.0%
Python Tutorial for Beginners 2 - Numbers and Math in Python.mp4 | 11 MB
↳ |████████████████████████████████████████████| 100.0%
Python Tutorial for Beginners 3 - Variables and Inputs.mp4 | 15 MB
↳ |████████████████████████████████████████████| 100.0%
Python Tutorial for Beginners 4 - Built-in Modules and Functions.mp4 | 16 MB
↳ |████████████████████████████████████████████| 100.0%
Python Tutorial for Beginners 5 - Save and Run Python files py.mp4 | 37 MB
↳ |████████████████████████████████████████████| 100.0%
Python Tutorial for Beginners 6 - Strings.mp4 | 78 MB
↳ |███████████████████████████████████ | 79.6%
当然除了默认的命令配置,还可以支持查看 list,查看字幕,筛选语言等等,具体的命令如下:
usage: pytube [-h] [--version] [--itag ITAG] [-r RESOLUTION] [-l] [-v]
[--logfile LOGFILE] [--build-playback-report] [-c CAPTION_CODE]
[-lc] [-t TARGET] [-a [AUDIO]] [-f [FFMPEG]]
[url]
Command line application to download youtube videos.
positional arguments:
url The YouTube /watch or /playlist url
optional arguments:
-h, --help show this help message and exit
--version show program's version number and exit
--itag ITAG The itag for the desired stream
-r RESOLUTION, --resolution RESOLUTION
The resolution for the desired stream
-l, --list The list option causes pytube cli to return a list of
streams available to download
-v, --verbose Verbosity level, use up to 4 to increase logging -vvvv
--logfile LOGFILE logging debug and error messages into a log file
--build-playback-report
Save the html and js to disk
-c CAPTION_CODE, --caption-code CAPTION_CODE
Download srt captions for given language code. Prints
available language codes if no argument given
-lc, --list-captions List available caption codes for a video
-t TARGET, --target TARGET
The output directory for the downloaded stream.
Default is current working directory
-a [AUDIO], --audio [AUDIO]
Download the audio for a given URL at the highest
bitrate availableDefaults to mp4 format if none is
specified
-f [FFMPEG], --ffmpeg [FFMPEG]
Downloads the audio and video stream for resolution
providedIf no resolution is provided, downloads the
best resolutionRuns the command line program ffmpeg to
combine the audio and video
更多详细的说明可以参考官方文档:https://python-pytube.readthedocs.io/en/latest/user/cli.html
代码使用
当然除了这些,pytube 还支持以 Python 编程的方式来进行下载,同时提供了便捷的链式操作,比如这段代码:
>>> from pytube import YouTube
>>> YouTube('https://youtu.be/2lAe1cqCOXo').streams.first().download()
>>> yt = YouTube('http://youtube.com/watch?v=2lAe1cqCOXo')
>>> yt.streams
... .filter(progressive=True, file_extension='mp4')
... .order_by('resolution')
... .desc()
... .first()
... .download()
这里大家可以看到,要使用 pytube,只需要导入其中的 YouTube 这个类,然后传入 URL 声明 YouTube 对象就好了。接着我们可以直接调用其 streams 方法获取所有的视频源,然后可以通过 first 或者 filter 或者 order 等进行排序或筛选等处理,然后最后调用 download 方法就可以执行下载了。
下面我们来剖析一下具体是怎么回事。
首先我们来声明一下 YouTube 对象:
>>> from pytube import YouTube
>>> yt = YouTube('https://youtu.be/2lAe1cqCOXo')
>>> yt
<pytube.__main__.YouTube object at 0x7f88901e9890>
然后看看 streams 是什么:
>>> yt.streams
[<Stream: itag="18" mime_type="video/mp4" res="360p" fps="24fps" vcodec="avc1.42001E" acodec="mp4a.40.2" progressive="True" type="video">, <Stream: itag="22" mime_type="video/mp4" res="720p" fps="24fps" vcodec="avc1.64001F" acodec="mp4a.40.2" progressive="True" type="video">, <Stream: itag="137" mime_type="video/mp4" res="1080p" fps="24fps" vcodec="avc1.640028" progressive="False" type="video">, <Stream: itag="248" mime_type="video/webm" res="1080p" fps="24fps" vcodec="vp9" progressive="False" type="video">, <Stream: itag="399" mime_type="video/mp4" res="1080p" fps="24fps" vcodec="av01.0.08M.08" progressive="False" type="video">, <Stream: itag="136" mime_type="video/mp4" res="720p" fps="24fps" vcodec="avc1.4d401f" progressive="False" type="video">, <Stream: itag="247" mime_type="video/webm" res="720p" fps="24fps" vcodec="vp9" progressive="False" type="video">, <Stream: itag="398" mime_type="video/mp4" res="720p" fps="24fps" vcodec="av01.0.05M.08" progressive="False" type="video">, <Stream: itag="135" mime_type="video/mp4" res="480p" fps="24fps" vcodec="avc1.4d401e" progressive="False" type="video">, <Stream: itag="244" mime_type="video/webm" res="480p" fps="24fps" vcodec="vp9" progressive="False" type="video">, <Stream: itag="397" mime_type="video/mp4" res="480p" fps="24fps" vcodec="av01.0.04M.08" progressive="False" type="video">, <Stream: itag="134" mime_type="video/mp4" res="360p" fps="24fps" vcodec="avc1.4d401e" progressive="False" type="video">, <Stream: itag="243" mime_type="video/webm" res="360p" fps="24fps" vcodec="vp9" progressive="False" type="video">, <Stream: itag="396" mime_type="video/mp4" res="360p" fps="24fps" vcodec="av01.0.01M.08" progressive="False" type="video">, <Stream: itag="133" mime_type="video/mp4" res="240p" fps="24fps" vcodec="avc1.4d4015" progressive="False" type="video">, <Stream: itag="242" mime_type="video/webm" res="240p" fps="24fps" vcodec="vp9" progressive="False" type="video">, <Stream: itag="395" mime_type="video/mp4" res="240p" fps="24fps" vcodec="av01.0.00M.08" progressive="False" type="video">, <Stream: itag="160" mime_type="video/mp4" res="144p" fps="24fps" vcodec="avc1.4d400c" progressive="False" type="video">, <Stream: itag="278" mime_type="video/webm" res="144p" fps="24fps" vcodec="vp9" progressive="False" type="video">, <Stream: itag="394" mime_type="video/mp4" res="144p" fps="24fps" vcodec="av01.0.00M.08" progressive="False" type="video">, <Stream: itag="140" mime_type="audio/mp4" abr="128kbps" acodec="mp4a.40.2" progressive="False" type="audio">, <Stream: itag="249" mime_type="audio/webm" abr="50kbps" acodec="opus" progressive="False" type="audio">, <Stream: itag="250" mime_type="audio/webm" abr="70kbps" acodec="opus" progressive="False" type="audio">, <Stream: itag="251" mime_type="audio/webm" abr="160kbps" acodec="opus" progressive="False" type="audio">]
>> type(yt.streams)
<class 'pytube.query.StreamQuery'>
可以看到这里 streams 是一个 StreamQuery 对象,然后输出出来看起来像是一个列表,其中包含了一个个 stream 对象。
所以,StreamQuery 就是我们需要重点关注的对象了。
比如接下来我们使用 filter 或者 order_by 方法进行处理:
>>> type(yt.streams.filter(file_extension='mp4'))
<class 'pytube.query.StreamQuery'>
可以看到它依然还是一个 StreamQuery 对象。
然后根据分辨率进行排序:
>>> type(yt.streams.filter(file_extension='mp4').order_by('resolution'))
<class 'pytube.query.StreamQuery'>
还是一样,返回的还是 StreamQuery 对象。
这下明白为什么它可以进行链式操作了吧,因为每次 filter 或者 order_by 对象返回的依然还是 StreamQuery 对象,依然还是可以调用对应的方法的。
不过也不是每一个都是支持链式操作的,比如接下来我们对 StreamQuery 对象调用 first 方法:
>>> yt.streams.first()
<Stream: itag="18" mime_type="video/mp4" res="360p" fps="24fps" vcodec="avc1.42001E" acodec="mp4a.40.2" progressive="True" type="video">
>>> type(yt.streams.first())
<class 'pytube.streams.Stream'>
看到这里返回的就是单个 Stream 了。
对于 Stream 对象,我们最常用的就是 download 方法了。
yt.streams.first().download()
调用完毕之后,视频就会下载在运行目录中。
以上我们就介绍了利用命令行和代码进行视频下载的过程。
更多
当然这个库还有很多强大的功能,都在文档 https://python-pytube.readthedocs.io/en/latest/ 写得很清楚了,这里带大家稍微看下。
比如获取视频的属性:
>>> yt.title
YouTube Rewind 2019: For the Record | #YouTubeRewind
获取视频的缩略图:
>>> yt.thumbnail_url
'https://i.ytimg.com/vi/2lAe1cqCOXo/maxresdefault.jpg'
在初始化的时候设置处理方法或者设置代理:
>>> yt = YouTube(
'http://youtube.com/watch?v=2lAe1cqCOXo',
on_progress_callback=progress_func,
on_complete_callback=complete_func,
proxies=my_proxies
)
关于 filter 的一些用法,可以参考 https://python-pytube.readthedocs.io/en/latest/user/streams.html#filtering-streams,比如说过滤只保留有音频的流媒体:
>>> yt.streams.filter(only_audio=True)
[<Stream: itag="140" mime_type="audio/mp4" abr="128kbps" acodec="mp4a.40.2" progressive="False" type="audio">,
<Stream: itag="249" mime_type="audio/webm" abr="50kbps" acodec="opus" progressive="False" type="audio">,
<Stream: itag="250" mime_type="audio/webm" abr="70kbps" acodec="opus" progressive="False" type="audio">,
<Stream: itag="251" mime_type="audio/webm" abr="160kbps" acodec="opus" progressive="False" type="audio">]
保留 mp4 后缀的视频:
>>> yt.streams.filter(file_extension='mp4')
[<Stream: itag="18" mime_type="video/mp4" res="360p" fps="30fps" vcodec="avc1.42001E" acodec="mp4a.40.2" progressive="True" type="video">,
<Stream: itag="22" mime_type="video/mp4" res="720p" fps="30fps" vcodec="avc1.64001F" acodec="mp4a.40.2" progressive="True" type="video">,
<Stream: itag="137" mime_type="video/mp4" res="1080p" fps="30fps" vcodec="avc1.640028" progressive="False" type="video">,
...
<Stream: itag="394" mime_type="video/mp4" res="None" fps="30fps" vcodec="av01.0.00M.08" progressive="False" type="video">,
<Stream: itag="140" mime_type="audio/mp4" abr="128kbps" acodec="mp4a.40.2" progressive="False" type="audio">]
比如获取字幕:
>>> yt = YouTube('http://youtube.com/watch?v=2lAe1cqCOXo')
>>> yt.captions
{'ar': <Caption lang="Arabic" code="ar">, 'zh-HK': <Caption lang="Chinese (Hong Kong)" code="zh-HK">, 'zh-TW': <Caption lang="Chinese (Taiwan)" code="zh-TW">, ...
这里各国语言的字幕几乎都有。
另外还可以把字幕打印出来,比如输出 srt 格式:
>>> caption = yt.captions.get_by_language_code('en')
>>> print(caption.generate_srt_captions())
1
00:00:10,200 --> 00:00:11,140
K-pop!
2
00:00:13,400 --> 00:00:16,200
That is so awkward to watch.
...
对于播放列表的处理,比如新建 Playlist 对象,然后取出每一个视频的第一个视频流并下载:
>>> from pytube import Playlist
>>> p = Playlist('https://www.youtube.com/playlist?list=PLS1QulWo1RIaJECMeUT4LFwJ-ghgoSH6n')
>>> for video in p.videos:
>>> video.streams.first().download()
另外还有一些异常处理机制:
>>> from pytube import Playlist, YouTube
>>> playlist_url = 'https://youtube.com/playlist?list=special_playlist_id'
>>> p = Playlist(playlist_url)
>>> for url in p.video_urls:
... try:
... yt = YouTube(url)
... except VideoUnavailable:
... print(f'Video {url} is unavaialable, skipping.')
... else:
... print(f'Downloading video: {url}')
... yt.streams.first().download()
总之,使用这个库,我们不仅可以使用命令行方便地下载 Youtube 视频和播放列表,还可以使用代码灵活地控制,一举两得!
往期精彩文章: