0

这是我尝试下载任何官方视频时总是遇到的错误,但在使用某些在线下载应用程序时会下载相同的视频。

  KeyError    Traceback (most recent call last)
~\anaconda3\lib\site-packages\pytube\extract.py in apply_descrambler(stream_data, key)
--> 297                 for format_item in formats
~\anaconda3\lib\site-packages\pytube\extract.py in <listcomp>(.0)
    296                 }
--> 297                 for format_item in formats
    298             ]
KeyError: 'url'

During handling of the above exception, another exception occurred:

KeyError      Traceback (most recent call last)
<ipython-input-1-796467b30bec> in <module>
      7 import cv2
      8 
----> 9 video = YouTube('https://www.youtube.com/watch?v=tDq3fNew1rU')
~\anaconda3\lib\site-packages\pytube\__main__.py in __init__(self, url, defer_prefetch_init, on_progress_callback, on_complete_callback, proxies)
     90         if not defer_prefetch_init:
     91             self.prefetch()
---> 92             self.descramble()
     94     def descramble(self) -> None:
~\anaconda3\lib\site-packages\pytube\__main__.py in descramble(self)
    130             if not self.age_restricted and fmt in self.vid_info:
    131                 apply_descrambler(self.vid_info, fmt)
--> 132             apply_descrambler(self.player_config_args, fmt)
    134             if not self.js:

~\anaconda3\lib\site-packages\pytube\extract.py in apply_descrambler(stream_data, key)
    299         except KeyError:
    300             cipher_url = [
--> 301                 parse_qs(formats[i]["cipher"]) for i, data in enumerate(formats)
    302             ]
    303             stream_data[key] = [
~\anaconda3\lib\site-packages\pytube\extract.py in <listcomp>(.0)
    299         except KeyError:
    300             cipher_url = [
--> 301                 parse_qs(formats[i]["cipher"]) for i, data in enumerate(formats)
    302             ]
    303             stream_data[key] = [

KeyError: 'cipher'

所以任何人都可以帮助我解决这个错误

4

2 回答 2

0

我也有同样的问题。我通过这样做解决了它:

  1. 转到安装site-packages/pytub/extract.py位置pytube
  2. 找到这条线:parse_qs(formats[i]["cipher"]) for i, data in enumerate(formats)
  3. 替换["cipher"]["signatureCipher"]
  4. 完毕。

来源在这里

于 2020-06-13T13:59:07.117 回答
0
#TODO: Actually due to some sudden changes on youtube some changes have to made on this API too..
# ? just use this line before starting any pytube script:
# ! pytube.__main__.apply_descrambler = __pre__.apply_descrambler

# The below imports are required by the patch
import json
from urllib.parse import parse_qs, unquote

# This function is based off on the changes made in
# https://github.com/nficano/pytube/pull/643

    def apply_descrambler(stream_data, key):
        """Apply various in-place transforms to YouTube's media stream data.
        Creates a ``list`` of dictionaries by string splitting on commas, then
        taking each list item, parsing it as a query string, converting it to a
        ``dict`` and unquoting the value.
        :param dict stream_data:
            Dictionary containing query string encoded values.
        :param str key:
            Name of the key in dictionary.
        **Example**:
        >>> d = {'foo': 'bar=1&var=test,em=5&t=url%20encoded'}
        >>> apply_descrambler(d, 'foo')
        >>> print(d)
        {'foo': [{'bar': '1', 'var': 'test'}, {'em': '5', 't': 'url encoded'}]}
        """
        otf_type = "FORMAT_STREAM_TYPE_OTF"
    
        if key == "url_encoded_fmt_stream_map" and not stream_data.get(
            "url_encoded_fmt_stream_map"
        ):
            formats = json.loads(stream_data["player_response"])["streamingData"]["formats"]
            formats.extend(
                json.loads(stream_data["player_response"])["streamingData"][
                    "adaptiveFormats"
                ]
            )
            try:
                stream_data[key] = [
                    {
                        "url": format_item["url"],
                        "type": format_item["mimeType"],
                        "quality": format_item["quality"],
                        "itag": format_item["itag"],
                        "bitrate": format_item.get("bitrate"),
                        "is_otf": (format_item.get("type") == otf_type),
                    }
                    for format_item in formats
                ]
            except KeyError:
                cipher_url = []
                for data in formats:
                    cipher = data.get("cipher") or data["signatureCipher"]
                    cipher_url.append(parse_qs(cipher))
                stream_data[key] = [
                    {
                        "url": cipher_url[i]["url"][0],
                        "s": cipher_url[i]["s"][0],
                        "type": format_item["mimeType"],
                        "quality": format_item["quality"],
                        "itag": format_item["itag"],
                        "bitrate": format_item.get("bitrate"),
                        "is_otf": (format_item.get("type") == otf_type),
                    }
                    for i, format_item in enumerate(formats)
                ]
        else:
            stream_data[key] = [
                {k: unquote(v) for k, v in parse_qsl(i)}
                for i in stream_data[key].split(",")
            ]

该文件是在其中一个问题中发布的(在 pytube GitHub 中),只需每次在您的主文件中导入它,然后pytube.__main__.apply_descrambler = __pre__.apply_descrambler 在您的文件中使用该行。

这会检测密码或密码签名并进行一些必要的更改。

于 2020-10-21T02:32:20.017 回答