Yotazo Lab.

ほぼ自分用。でも誰かの役に立つかもしれない話題

pytubeでYouTubeの動画ダウンローダーを作る

f:id:yotazo:20180125162038p:plain

目次

Windowsでpytubeを動かすまで

pytubeというpythonのライブラリを見つけました。

https://github.com/nficano/pytube

簡単にYouTubeの動画をダウンロードできると書いてあって、ちょっと面白そうなので試してみた記録です。

Windowspythonを入れる

Windowsでやりたいので、まずはWindowspythonを入れるところからのスタート。pythonもせっかくなので3を入れてみようと思います。

こちらからWindows用のpythonインストーラをダウンロード。
https://www.python.org/downloads/windows/

64bit環境なので、Python 3.6.4 - Windows x86-64 executable installer とかでいいんじゃないでしょうか。

f:id:yotazo:20180124152142j:plain
pathを通すにチェックを入れてInstall Nowをクリックするとインストール開始。
pipもインストールされるようです。

インストールが終わったら、コマンドプロンプトを立ち上げて「python」と打ってみて、pythonが立ち上がればOK。

いったん、Ctrl+Z > Enterでpythonを抜けます。

pytubeを入れる

すでにpipが使えるはずなので、Windowsコマンドプロンプトを立ち上げて、

pip install pytube

これだけ。

f:id:yotazo:20180124154614j:plain

こんな画面が出てあっけなくインストール完了。
バージョンは8.0.2のようです。

pytubeの実行

Eドライブ直下に「py」というフォルダを作り、ここを作業フォルダにしようと思います。

説明書のサンプルでは対話式で進めていますが、せっかくなのでテキストエディタとかIDLEでスクリプトを書きます。

from pytube import YouTube
YouTube('http://youtube.com/watch?v=9bZkp7q19f0').streams.first().download()

こんな感じでサンプル通りに書いたものを作業フォルダ「py」の中に、test.pyとして保存します。

コマンドでEドライブのpyに移動して、python test.py というふうに実行します。

しばし沈黙の後、プロンプトが戻ります。

f:id:yotazo:20180124164923p:plain

おや、何もおきないかな? と思いましたが、

pyフォルダの中に動画ファイルができていました。

無事成功です。
ほんと簡単ですね。

もう少しつっこんだpytubeの使い方

せっかくなので、もう少し詳しいpytubeの使い方を見ていきます。

※適当なので、正確な解説はこちらのドキュメントをどうぞ!
https://python-pytube.readthedocs.io/en/latest/

YouTubeオブジェクト

from pytube import YouTube
yt = YouTube('https://www.youtube.com/watch?v=ssuiqtreiBg')

このように、YouTube()クラスに動画のURLを渡すとYouTubeオブジェクト(ここではyt)ができます。yt.title で動画のタイトル、yt.thumbnail_url で動画のサムネイルのURLが取得できたりします。

実例

from pytube import YouTube
yt = YouTube('https://www.youtube.com/watch?v=ssuiqtreiBg')
print(yt.title)
print(yt.thumbnail_url)

実行すると、このような結果になります。
f:id:yotazo:20180126132328p:plain

StreamQueryオブジェクト

yt.streams はStreamQueryというオブジェクトになります。これは、その動画に対してどのようなフォーマット形式の動画や音声が用意されているのかの一覧情報です。説明よりも中身を見てみるほうがわかりやすいと思うので、まずは・・・

all()でStreamQueryの中身を全部見る

all()でStreamQueryの中身を全部見ることができます。データはリストなのでforで出力してみます。

from pytube import YouTube
yt = YouTube('https://www.youtube.com/watch?v=ssuiqtreiBg')

s = yt.streams.all()
for i in s:
 print (i)

f:id:yotazo:20180126155534p:plain

ズラっと出てきましたが、この動画にこれだけフォーマットの用意があるよーということです。中には動画だけ音声だけのものもありますが、これは、Dynamic Adaptive Streaming over HTTP (DASH)という技術をサポートするためのものだそうです。詳しくないのでアレですが、環境などによってこれらの動画×音声の組み合わせを切り替えて再生できるそうです。

なるほど。

一方、動画と音声が一つになっている旧来の方式(progressive download)も用意されています。ただしこれは720p以下のものしかないそうです。

filterを使う

このリストに対して、いろいろな条件のフィルタをかけることでデータの絞り込みをすることができます。

progressiveを全部

yt.streams.filter(progressive=True).all()


DASH(adaptive)を全部

yt.streams.filter(adaptive=True).all()


mime_typeがvideo/mp4を全部

yt.streams.filter(mime_type='video/mp4').all()


mime_typeの)typeがvideoを全部

yt.streams.filter(type='video').all()


mime_typeの)subtypeがmp4を全部

yt.streams.filter(subtype='mp4').all()


filterの重ねがけ

subtypeがmp4+progressiveを全部

yt.streams.filter(subtype='mp4', progressive=True).all()

この書式でも可です

yt.streams.filter(subtype='mp4').filter(progressive=True).all()
リストを並び替える

order_by()を使うことでリストの並び替えができます。order_by()に並び順に使用する属性を渡し、asc() またはdesc()で昇順/降順を指定します。

progressiveを解像度の高い順に全て並べる

yt.streams.filter(progressive=True).order_by('resolution').desc().all()

※注意
Note that order_by cannot be used if your attribute is undefined in any of the Stream instances, so be sure to apply a filter to remove those before calling it.

リストに、order_byに使う属性を持たないデータが混じってちゃダメ。

例えば、解像度を持たない音声のみのストリームが入っているリストに対しては、解像度での order_byはできないということです。

具体的には、mp4で一番解像度の高いストリームを取得しようと思い、下記のようにしたとします。

yt.streams.filter(subtype='mp4').order_by('resolution').desc().first()

するとこんなエラーが出ます。

TypeError: '<' not supported between instances of 'NoneType' and 'str'

subtype='mp4'というフィルタリングだと、音声のみのストリームがリストに入ってきます。すると、このリストに対しては解像度でorder_byができないというわけです。

これを回避するには、

対象をvideo/mp4にするとか、

yt.streams.filter(mime_type='video/mp4').order_by('resolution').desc().first()

progressiveにしてみるとか

yt.streams.filter(progressive=True).order_by('resolution').desc().all()

うまいことorder_byができるようにフィルタしないといけません。

リストの先頭/最後を指定して取ってくる

first()
last()
リストの一番先頭・最後のStreamを取ります。解像度の高い順に並べて、first()を取れば一番解像度の高いデータを指定できます。

itagで指定して取ってくる

get_by_itag(itag)
リストの中からピンポイントでデータを指定したい時に、itagの番号でデータを拾うことができます。

簡単な対話式ダウンローダ

飽きてきたちょっと長くなったので、
対話式のダウンローダーをまとめのサンプルとして置いて、いったんしめます。

from pytube import YouTube

url = input("Enter YouTube Video URL : ")
yt = YouTube(url)

def done(stream, file_handle):
    print("Done")

list = yt.streams.filter(progressive = True).all()
for i, j in enumerate(list):
    print('[{0}]:{1}'.format(i, j))

target = int(input("Enter Stream# : "))
yt.register_on_complete_callback(done)
list[target].download()

実行すると、動画のURLを入れろと言われます。
f:id:yotazo:20180202093143p:plain


入れるURLはhttps://www.youtube.com/watch?v=hogehoge のような形式です。後ろに他のパラメーターがゴチャゴチャとくっついていても大丈夫みたいです。URLを入れてEnterを押して少しすると、フォーマット一覧が出てきて、欲しい番号を入れろと言われます。
f:id:yotazo:20180202093149p:plain



先頭の[0]とか[1]の番号を入れます。ここでは0番がよさそうなので、0と入力。ダウンロードが終わるとDoneと出て終了です。
f:id:yotazo:20180202093155p:plain

以上

※フィルタをかけているので、このサンプルではprogressive形式だけがリストアップされます。他の形式も見たい場合はフィルタの部分をいじってください。

次はDASH形式の高画質動画と高音質音声の合体に挑戦!
いつになるかは未定w

mp3への変換あたりからにしようかしら・・・

2018/2/8 追記

pytubeがエラーを吐いて使えなくなりました。
pytubeが9.0.4にバージョンアップしているようなので、バージョンアップしてみたのですが、またエラー。

あれ? でもエラーが変わりました。

from pytube.contrib.playlist import Playlist
ModuleNotFoundError: No module named 'pytube.contrib'

モジュールの読み込みができていないようです。
pytubeのインストールされている場所を見てみると・・・
なんと、contribフォルダがありませんw

pip経由でインストールすると、このフォルダが入らないようです。
作者が入れ忘れたのかな?

ここからcontribとその中身を手動で入れたら動きました。やれやれ。
https://github.com/nficano/pytube


Windowsのpytubeはこのあたりに入っています。
C:\Users\********\AppData\Local\Programs\Python\Python36\Lib\site-packages\pytube

さらに追記
上記の問題はfixされたようです