前回の続き
また見てない方は前回はここからどうぞ。
前回はextractorの基礎中の基礎を書きました。
次は、エラーハンドリングやユーザーに対してエラーや警告をどうやって表示するのかをやって行きます。
最終目標
前回のページをもう一回ダウンロードさせてみる
ここで、前回のwhowatchの生放送を再度ダウンロードさせてみましょう。
$ python3 -m youtube_dl https://whowatch.tv/viewer/18667149
[WhoWatch] 18667149: Downloading JSON metadata
ERROR: An extractor error has occurred. (caused by KeyError('hls_url')); please report this issue on https://yt-dl.org/bug . Make sure you are using the latest version; see https://yt-dl.org/update on how to update. Be sure to call youtube-dl with the --verbose flag and include its complete output.
...ダウンロードできませんね
同じ方の最新の生放送に変わりました。
そうです。同じURLの生放送は終了してしまったのです。
問題を切り分ける
前回までのコードに少し追加して、何が返ってきたのかを見てみることにします。
live_data = self._download_json(api_url, video_id)
# デバッグ用: live_dataを表示する
self.to_screen(live_data)
その内容は、次のようになっています。
{'error_code': 'L-004', 'error_message': 'その配信は終了しています。(L-004)'}
エラー状態の返答が分かったので、この状態かどうかを調べることでエラーハンドリングができます。
これが終わったらself.to_screen(live_data)
はコメントアウトして下さい。
extractorで綺麗にエラーを投げる
ここで、最初のエラーを見てみましょう。
$ python3 -m youtube_dl https://whowatch.tv/viewer/18667149
[WhoWatch] 18667149: Downloading JSON metadata
ERROR: An extractor error has occurred. (caused by KeyError('hls_url')); please report this issue on https://yt-dl.org/bug . Make sure you are using the latest version; see https://yt-dl.org/update on how to update. Be sure to call youtube-dl with the --verbose flag and include its complete output.
具体的な例外のクラス名はKeyError
であると読み取れます。
dictにおけるKeyError
というのは、「キーが存在しない」場合を指します。1
返答を見ても分かるとおり、hls_url
はありません。この状態の時にNone
で返してくれれば簡単に区別できます。
少しdictのドキュメントを見ていくと、get(key[, default])
という正に探していたメソッドがありますので、これを使います。
# HLSのURL
hls_url = live_data.get('hls_url')
# hls_urlが無ければエラーを投げる
if not hls_url:
# ここでエラーを投げないと大変なことになる
こういう何らかのエラー(生放送が終了した、サーバーがなにかおかしい)を表すクラスとして、ExtractorError
があります。
from ..utils import ExtractorError
これの具体的な引数はソースコードを見てほしいので、ここでは結論だけ示します。
# hls_urlが無ければエラーを投げる
if not hls_url:
raise ExtractorError(live_data.get('error_message'), expected=True)
このようにすると、エラーは次のように変わります。
$ python3 -m youtube_dl https://whowatch.tv/viewer/18667149
[WhoWatch] 18667149: Downloading JSON metadata
ERROR: その配信は終了しています。(L-004)
この表示であれば分かりやすいと思います。
またバグの類ではないということを提示して、ダウンロードを諦めてもらうこともできます。
おわりに
今回は、extractorのエラーの投げ方を書きました。
次回は、別の生放送を使って動画のフォーマット情報以外の情報の取り出しをやっていきたいと思います。
ここまでご覧いただきありがとうございました。
次: 第3巻
付録: 今回のソースコード
# coding: utf-8
from __future__ import unicode_literals
from .common import InfoExtractor
from ..utils import ExtractorError
class WhoWatchIE(InfoExtractor):
_VALID_URL = r'https?://whowatch\.tv/viewer/(?P<id>\d+)/?'
def _real_extract(self, url):
video_id = self._match_id(url)
api_url = 'https://api.whowatch.tv/lives/' + video_id + '/play?referer=https%3A%2F%2Fwhowatch.tv%2F'
# URL、IDの順で指定する
live_data = self._download_json(api_url, video_id)
# デバッグ用: live_dataを表示する
# self.to_screen(live_data)
# HLSのURL
hls_url = live_data.get('hls_url')
# hls_urlが無ければエラーを投げる
if not hls_url:
raise ExtractorError(live_data.get('error_message'), expected=True)
# とりあえずHLSのフォーマットを検索する
formats = self._extract_m3u8_formats(
hls_url, video_id, ext='mp4', entry_protocol='m3u8_native',
m3u8_id='hls')
# 並び替える。これによって何も設定しない状態で最高画質をダウンロードするようにする
self._sort_formats(formats)
return {
'id': video_id,
# 鉤括弧があったので同時に外してしまう
'title': live_data['share_info']['live_title'][1:-1],
# フォーマット一覧
'formats': formats,
# これは生放送です
'is_live': True,
}
-
https://docs.python.org/3/library/stdtypes.html#mapping-types-dict
Return the item of d with key key. Raises a KeyError if key is not in the map.
↩