1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

youtube-dlのextractor書き方講座 2/4

Last updated at Posted at 2020-12-09

前回の続き

また見てない方は前回はここからどうぞ。
前回は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.

...ダウンロードできませんね

実際のウェブページではどのように見えているのでしょうか?
image.png

同じ方の最新の生放送に変わりました。
そうです。同じURLの生放送は終了してしまったのです。

問題を切り分ける

前回までのコードに少し追加して、何が返ってきたのかを見てみることにします。

whowatch.py
        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])という正に探していたメソッドがありますので、これを使います。

whowatch.py
        # HLSのURL
        hls_url = live_data.get('hls_url')

        # hls_urlが無ければエラーを投げる
        if not hls_url:
            # ここでエラーを投げないと大変なことになる

こういう何らかのエラー(生放送が終了した、サーバーがなにかおかしい)を表すクラスとして、ExtractorErrorがあります。

whowatch.py
from ..utils import ExtractorError

これの具体的な引数はソースコードを見てほしいので、ここでは結論だけ示します。

whowatch.py
        # 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巻

付録: 今回のソースコード

whowatch.py
# 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,
        }
  1. 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.

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?