Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

urllib.error.HTTPError: HTTP Error 403: Forbidden #399

Closed
NeverAskWhy opened this issue Jun 6, 2019 · 65 comments
Closed

urllib.error.HTTPError: HTTP Error 403: Forbidden #399

NeverAskWhy opened this issue Jun 6, 2019 · 65 comments

Comments

@NeverAskWhy
Copy link

Hi all,

I'm aware that there are some older issues with the same error, howevery I thought I would just give it a try. For some videos (like this one: https://www.youtube.com/watch?v=393C3pr2ioY ) I get a 403 error...others work fine though. Do you know of any workaround for that? I saw this thread in the older issue https://stackoverflow.com/questions/16627227/http-error-403-in-python-3-web-scraping but I'm not good enough in Python to find the right spot to implement it. Any help would be appreciated.

PS: I already updated to the most current version (9.5.0).

@Waarbubble
Copy link

I am having the same problem, but for me, it is random whether the same youtube link will generate a 403 or not. My current testing links are:
https://www.youtube.com/watch?v=pAgnJDJN4VA&index=117&list=PL3LCt07uiILKduYr52ZMYrE_PvbSuUdZM
https://www.youtube.com/watch?v=t9psCAWrISg&index=136&list=PL3LCt07uiILKduYr52ZMYrE_PvbSuUdZM
I am only trying to download the audio stream.

@Nowbob
Copy link

Nowbob commented Jun 7, 2019

It's a hack of a fix, but this is how I've got mine working for now (I'm running in python 2.7, you may need to fiddle depending on your version):
In pytube/request.py:
At line 4 I added:
from urllib2 import Request

And above line 21 (response = urlopen(url)):
req = Request(url, headers = {"User-Agent": "Mozilla/5.0"})

And then replace the line below:
response = urlopen(url)
with:
response = urlopen(req)

@Waarbubble
Copy link

Just tested the solution, keeps randomly giving 403, and then working again.

@NeverAskWhy
Copy link
Author

@Waarbubble : you mean you tested @Nowbob's solution?

@Waarbubble
Copy link

Waarbubble commented Jun 7, 2019

yes
Tested in python 3

@Nowbob
Copy link

Nowbob commented Jun 7, 2019

Yeah I was having the same "sometimes it works sometimes it doesn't" problem, but it's the best I could come up with in a short time.

@Waarbubble
Copy link

It was worth a try.

@NeverAskWhy
Copy link
Author

I'm doing something wrong...
In line for of request.py:
from urllib import request

then line 22/23:
req = request(url, headers = {"User-Agent": "Mozilla/5.0"})
response = urlopen(req)

now I'm getting this error:

self.watch_html = request.get(url=self.watch_url)

File "C:\Users\janvo\AppData\Local\Programs\Python\Python37-32\lib\site-packages\pytube\request.py", line 22, in get
req = request(url, headers = {"User-Agent": "Mozilla/5.0"})
TypeError: 'module' object is not callable

@Waarbubble
Copy link

If you are using python 3 the

fourth line needs to be from urllib.request import Request

and then line 22 will need a capital R in request

@NeverAskWhy
Copy link
Author

Thanks...I changed it now. It's behaving the same way...three times I got the 403-error and then it worked.

@hoetaek
Copy link

hoetaek commented Jun 11, 2019

Getting the same error. I tried all the solutions above. And some works and some don't.

@danielgordon10
Copy link

This got much more frequent for me today for some reason. The above solutions do not seem to work for the new cases. Example video https://www.youtube.com/watch?v=ZYoUXaU81Gk

@rafaelwastaken
Copy link

I believe I've managed to fix this by changing &signature= in line 64 of mixins.py to &sig=.

@Waarbubble
Copy link

The solution works for me, no more random 403

@danielgordon10
Copy link

danielgordon10 commented Jun 11, 2019

Neither suggested solution fixes my test video https://www.youtube.com/watch?v=ZYoUXaU81Gk

@rafaelwastaken
Copy link

rafaelwastaken commented Jun 11, 2019

@danielgordon10 What error are you getting? I just tried downloading that link and it seems to be working with the &sig= fix.

pytube https://www.youtube.com/watch?v=ZYoUXaU81Gk --list
<Stream: itag="43" mime_type="video/webm" res="360p" fps="30fps" vcodec="vp8.0" acodec="vorbis">
<Stream: itag="18" mime_type="video/mp4" res="360p" fps="30fps" vcodec="avc1.42001E" acodec="mp4a.40.2">
<Stream: itag="135" mime_type="video/mp4" res="480p" fps="30fps" vcodec="avc1.4d400b">
<Stream: itag="244" mime_type="video/webm" res="480p" fps="30fps" vcodec="vp9">
<Stream: itag="134" mime_type="video/mp4" res="360p" fps="30fps" vcodec="avc1.4d401e">
<Stream: itag="243" mime_type="video/webm" res="360p" fps="30fps" vcodec="vp9">
<Stream: itag="133" mime_type="video/mp4" res="240p" fps="30fps" vcodec="avc1.4d400c">
<Stream: itag="242" mime_type="video/webm" res="240p" fps="30fps" vcodec="vp9">
<Stream: itag="160" mime_type="video/mp4" res="144p" fps="30fps" vcodec="avc1.4d400b">
<Stream: itag="278" mime_type="video/webm" res="144p" fps="30fps" vcodec="vp9">
<Stream: itag="140" mime_type="audio/mp4" abr="128kbps" acodec="mp4a.40.2">
<Stream: itag="171" mime_type="audio/webm" abr="128kbps" acodec="vorbis">
<Stream: itag="249" mime_type="audio/webm" abr="50kbps" acodec="opus">
<Stream: itag="250" mime_type="audio/webm" abr="70kbps" acodec="opus">
<Stream: itag="251" mime_type="audio/webm" abr="160kbps" acodec="opus">
pytube https://www.youtube.com/watch?v=ZYoUXaU81Gk --itag 251
Мисс Новоуральск 2012.webm | 7446370 bytes

@danielgordon10
Copy link

So I am able to get the stream but I can't download it.

import pytube
video_url = 'https://www.youtube.com/watch?v=ZYoUXaU81Gk'
yt = pytube.YouTube(video_url)
streams = yt.streams
streams = (
        streams.filter(progressive=True, custom_filter_functions=[lambda x: x.resolution is not None])
        .order_by("resolution")
        .all()
)
stream = streams[0]
video = stream.download()

Then I get the urllib.error.HTTPError

    video = stream.download()
  File "/home/xkcd/miniconda3/envs/video-env/lib/python3.7/site-packages/pytube/streams.py", line 217, in download
    bytes_remaining = self.filesize
  File "/home/xkcd/miniconda3/envs/video-env/lib/python3.7/site-packages/pytube/streams.py", line 164, in filesize
    headers = request.get(self.url, headers=True)
  File "/home/xkcd/miniconda3/envs/video-env/lib/python3.7/site-packages/pytube/request.py", line 22, in get
    response = urlopen(url)
  File "/home/xkcd/miniconda3/envs/video-env/lib/python3.7/urllib/request.py", line 222, in urlopen
    return opener.open(url, data, timeout)
  File "/home/xkcd/miniconda3/envs/video-env/lib/python3.7/urllib/request.py", line 531, in open
    response = meth(req, response)
  File "/home/xkcd/miniconda3/envs/video-env/lib/python3.7/urllib/request.py", line 641, in http_response
    'http', request, response, code, msg, hdrs)
  File "/home/xkcd/miniconda3/envs/video-env/lib/python3.7/urllib/request.py", line 569, in error
    return self._call_chain(*args)
  File "/home/xkcd/miniconda3/envs/video-env/lib/python3.7/urllib/request.py", line 503, in _call_chain
    result = func(*args)
  File "/home/xkcd/miniconda3/envs/video-env/lib/python3.7/urllib/request.py", line 649, in http_error_default
    raise HTTPError(req.full_url, code, msg, hdrs, fp)
urllib.error.HTTPError: HTTP Error 403: Forbidden

@rafaelwastaken
Copy link

I've only used this in CLI before so I'm not sure, my guess would be to check if it's importing the correct one.

@danielgordon10
Copy link

It works fine for other videos...

@danielgordon10
Copy link

I think I have a working fix now for this and a related issue (#392). It's not pretty, but it seems to get the job done.
in mixins.py

        if ('signature=' in url or 
                ('s' not in stream and 
                 ('&sig=' in url or '&lsig=' in url))):
            # For certain videos, YouTube will just provide them pre-signed, in
            # which case there's no real magic to download them and we can skip
            # the whole signature descrambling entirely.
            logger.debug('signature found, skip decipher')
            continue

        if js is not None:
            signature = cipher.get_signature(js, stream['s'])
        else:
            # signature not present in url (line 33), need js to descramble
            # TypeError caught in __main__
            raise TypeError('JS is None')

        logger.debug(
            'finished descrambling signature for itag=%s\n%s',
            stream['itag'], pprint.pformat(
                {
                    's': stream['s'],
                    'signature': signature,
                }, indent=2,
            ),
        )
        stream_manifest[i]['url'] = url + '&sig=' + signature

@rsistema
Copy link

I believe I've managed to fix this by changing &signature= in line 64 of mixins.py to &sig=.

I tried the first fix from @Nowbob, but the problem persisted.
Change the line 64 as you said and now it's working again. Perfectly on Python 2.7

@t4ke0
Copy link

t4ke0 commented Jun 18, 2019

still have that error !?

@genesysvip
Copy link

I think I have a working fix now for this and a related issue (#392). It's not pretty, but it seems to get the job done.
in mixins.py

        if ('signature=' in url or 
                ('s' not in stream and 
                 ('&sig=' in url or '&lsig=' in url))):
            # For certain videos, YouTube will just provide them pre-signed, in
            # which case there's no real magic to download them and we can skip
            # the whole signature descrambling entirely.
            logger.debug('signature found, skip decipher')
            continue

        if js is not None:
            signature = cipher.get_signature(js, stream['s'])
        else:
            # signature not present in url (line 33), need js to descramble
            # TypeError caught in __main__
            raise TypeError('JS is None')

        logger.debug(
            'finished descrambling signature for itag=%s\n%s',
            stream['itag'], pprint.pformat(
                {
                    's': stream['s'],
                    'signature': signature,
                }, indent=2,
            ),
        )
        stream_manifest[i]['url'] = url + '&sig=' + signature

It's work thank you!
But I modify two file mixins.py & cipher.py
% mixins.py
ref #402
if ('signature=' in url) or ('&sig=' in url) or ('&lsig=' in url):
to
if ('signature=' in url or
('s' not in stream and
('&sig=' in url or '&lsig=' in url))):

and

stream_manifest[i]['url'] = url + '&signature=' + signature
to
stream_manifest[i]['url'] = url + '&sig=' + signature

and change pattern in cipher.py
pattern = [
r'yt.akamaized.net/)\s*||\s*'
r'.?\sc\s*&&\sd.set([^,]+\s,\s*(?:encodeURIComponent'
r'\s*()?(?P[a-zA-Z0-9$]+)(',
r'.sig||(?P[a-zA-Z0-9$]+)(',
r'\bc\s*&&\sd.set([^,]+\s,\s*(?:encodeURIComponent'
r'\s*()?(?P[a-zA-Z0-9$]+)(',
]
to
pattern = [
r'\b[cs]\s*&&\s*[adf].set([^,]+\s*,\sencodeURIComponent\s(\s*(?P[a-zA-Z0-9$]+)(',
r'\b[a-zA-Z0-9]+\s*&&\s*[a-zA-Z0-9]+.set([^,]+\s*,\sencodeURIComponent\s(\s*(?P[a-zA-Z0-9$]+)(',
r'(?P[a-zA-Z0-9$]+)\s*=\sfunction(\sa\s*)\s*{\sa\s=\sa.split(\s""\s*)',
r'(["'])signature\1\s*,\s*(?P[a-zA-Z0-9$]+)(',
r'.sig||(?P[a-zA-Z0-9$]+)(',
r'yt.akamaized.net/)\s*||\s*.?\s[cs]\s*&&\s*[adf].set([^,]+\s*,\s*(?:encodeURIComponent\s*()?\s*'
r'(?P[a-zA-Z0-9$]+)(',
r'\b[cs]\s*&&\s*[adf].set([^,]+\s*,\s*(?P[a-zA-Z0-9$]+)(',
r'\b[a-zA-Z0-9]+\s*&&\s*[a-zA-Z0-9]+.set([^,]+\s*,\s*(?P[a-zA-Z0-9$]+)(',
r'\bc\s*&&\sa.set([^,]+\s,\s*([^)])\s(\s*(?P[a-zA-Z0-9$]+)(',
r'\bc\s*&&\s*[a-zA-Z0-9]+.set([^,]+\s*,\s*([^)])\s(\s*(?P[a-zA-Z0-9$]+)(',
r'\bc\s*&&\s*[a-zA-Z0-9]+.set([^,]+\s*,\s*([^)])\s(\s*(?P[a-zA-Z0-9$]+)('
]

I forget this issue number, someone can help me to link?
work on python 3.6, pytube 9.5.0, urllib3 1.25.3

@snwfdhmp
Copy link

I tried for 15 minutes before realising that : for the mixins.py fix, you have to replace the whole snippet, not just replace signature to sig.

Now it works, thanks a lot !

@ogspeace
Copy link

ogspeace commented Aug 27, 2019

With 9.5.1 (the latest downloaded) I tinkered with all the fixes from this thread and finally got it working. There are two separate issues that i had to tackle:

1. KeyError:['title'] and

2. "403: Forbidden"

1)FIrst one to solve was the KeyError:['title']
For some reason the 'title' key is not retrieved anymore in the root of the player_config_args dictionary, hence the error. Upon debugging of the req/reply I found It is instead present in "player_response/videoDetails/title", so edit main.py:

def title(self):
        #Get the video title.

        #:rtype: str

        try:
                tt1 = self.player_config_args['title']
        except:
                tt1 = self.player_config_args.get('player_response', {}).get('videoDetails', {}).get('title')
        finally:
                if not tt1:
                        tt1 = "Unknown YTube video"
        return tt1

and streams.py:

    def default_filename(self):
        """Generate filename based on the video title.

        :rtype: str
        :returns:
            An os file system compatible filename.
        """
        try:
                title = self.player_config_args['title']
        except:
                title = self.player_config_args.get('player_response', {}).get('videoDetails', {}).get('title')
        finally:
                if not title:
                        title = "Unknown YTube video"
        filename = safe_filename(title)
        return '{filename}.{s.subtype}'.format(filename=filename, s=self)

I did also apply the fix found in this thread to request.py about the Agent-User:
from urllib2 import Request
and

req = Request(url, headers = {"User-Agent": "Mozilla/5.0"})
    #response = urlopen(url)
    response = urlopen(req)

2)For the "403 Forbidden" I applied first the suggestion about mixins.py in the apply_signature function:

         if ('signature=' in url or
                ('s' not in stream and
                ('&sig=' in url or '&lsig=' in url))):

            # For certain videos, YouTube will just provide them pre-signed, in
            # which case there's no real magic to download them and we can skip
            # the whole signature descrambling entirely.
            logger.debug('signature found, skip decipher')
            continue

        if js is not None:
            signature = cipher.get_signature(js, stream['s'])
        else:
            # signature not present in url (line 33), need js to descramble
            # TypeError caught in __main__
            raise TypeError('JS is None')

        logger.debug(
            'finished descrambling signature for itag=%s\n%s',
            stream['itag'], pprint.pformat(
                {
                    's': stream['s'],
                    'signature': signature,
                }, indent=2,
            ),
        )
        stream_manifest[i]['url'] = url + '&sig=' + signature

then in the cipher.py I replaced the regex pattern as suggested in another post of this thread:

pattern = [
        r'\b[cs]\s*&&\s*[adf]\.set\([^,]+\s*,\s*encodeURIComponent\s*\(\s*(?P<sig>[a-zA-Z0-9$]+)\(',
        r'\b[a-zA-Z0-9]+\s*&&\s*[a-zA-Z0-9]+\.set\([^,]+\s*,\s*encodeURIComponent\s*\(\s*(?P<sig>[a-zA-Z0-9$]+)\(',
        r'(?P<sig>[a-zA-Z0-9$]+)\s*=\s*function\(\s*a\s*\)\s*{\s*a\s*=\s*a\.split\(\s*""\s*\)',
        r'(["\'])signature\1\s*,\s*(?P<sig>[a-zA-Z0-9$]+)\(',
        r'\.sig\|\|(?P<sig>[a-zA-Z0-9$]+)\(',
        r'yt\.akamaized\.net/\)\s*\|\|\s*.*?\s*[cs]\s*&&\s*[adf]\.set\([^,]+\s*,\s*(?:encodeURIComponent\s*\()?\s*(?P<si$',
        r'\b[cs]\s*&&\s*[adf]\.set\([^,]+\s*,\s*(?P<sig>[a-zA-Z0-9$]+)\(',
        r'\b[a-zA-Z0-9]+\s*&&\s*[a-zA-Z0-9]+\.set\([^,]+\s*,\s*(?P<sig>[a-zA-Z0-9$]+)\(',
        r'\bc\s*&&\s*a\.set\([^,]+\s*,\s*\([^)]*\)\s*\(\s*(?P<sig>[a-zA-Z0-9$]+)\(',
        r'\bc\s*&&\s*[a-zA-Z0-9]+\.set\([^,]+\s*,\s*\([^)]*\)\s*\(\s*(?P<sig>[a-zA-Z0-9$]+)\(',
        r'\bc\s*&&\s*[a-zA-Z0-9]+\.set\([^,]+\s*,\s*\([^)]*\)\s*\(\s*(?P<sig>[a-zA-Z0-9$]+)\('
    ]

@gitethis 's solutions work, and tried it on my scripts, however, here's a slight tweak for python3 users:

in request.py instead of: from urllib2 import Request

use this: from urllib.request import Request

/ogs

@jrial
Copy link

jrial commented Aug 27, 2019

Seeing as how this appears to be solved with the changes described in various comments, did anyone create a pull request already? I noticed one while quickly scanning this issue, but that one's CI tests failed.

@Algomorph
Copy link

@jrial ,

Unfortunately, I seem to have applied all the fixes so helpfully summarized by @ogspeace, and I'm still getting "urllib.error.HTTPError: HTTP Error 403: Forbidden"

@halfendt
Copy link

Thank you! Works for me as well on Python 3.6.5, urllib3 1.25.3, and PyTube 9.5.1.

To summarize the patches needed:

  1. mixins.py - patch by @danielgordon10 in #399 (comment)
  2. cipher.py - edit of @GravelCZ's patch by @nhatton96 at the bottom of #399 (comment)

This also worked very well for me.

@xyang5987
Copy link

I changed both mixins.py and cipher.py, but I still got HTTPError: Forbidden

@xyang5987
Copy link

I use Python 3.7 and pytube 9.5.2 with win 10.

@Algomorph
Copy link

Thank you! Works for me as well on Python 3.6.5, urllib3 1.25.3, and PyTube 9.5.1.

To summarize the patches needed:

  1. mixins.py - patch by @danielgordon10 in #399 (comment)
  2. cipher.py - edit of @GravelCZ's patch by @nhatton96 at the bottom of #399 (comment)

I tried this in Windows 10, and it did finally work. Python 3.7.4, PyTube 9.5.2 with the above 2 patches. I also had to apply the title retrieval patch in main.py and streams.py as outlined by @ogspeace. Did not have to mess with urllib for whatever reason, but maybe just got lucky on the ~50 videos I've tried.

@gittethis
Copy link

I use Python 3.7 and pytube 9.5.2 with win 10.

did you use also my patches on "title" retrieval for main.py and streams.py, as outlined and confirmed by @ogspeace ?

@Algomorph
Copy link

To keep things clear here, the 'title' retrieval patches fixed a separate issue, e.g. using you_tube_object.video after it's been created. It doesn't affect the "HTTPError: Forbidden" issue, and as such should be kept in a separate PR.

@eyobofficial
Copy link

For me, the errors are not occurring randomly. They always seem to occur when I attempt to download music videos.

@santoslopes
Copy link

Not working
It seems to be a good option to download youtube contents but no support, therefore let's look after other options.

VanDenHendeSimon referenced this issue in VanDenHendeSimon/youtube-downloader Oct 28, 2019
@MrSlagovich
Copy link

I think I have a working fix now for this and a related issue (#392). It's not pretty, but it seems to get the job done.
in mixins.py

        if ('signature=' in url or 
                ('s' not in stream and 
                 ('&sig=' in url or '&lsig=' in url))):
            # For certain videos, YouTube will just provide them pre-signed, in
            # which case there's no real magic to download them and we can skip
            # the whole signature descrambling entirely.
            logger.debug('signature found, skip decipher')
            continue

        if js is not None:
            signature = cipher.get_signature(js, stream['s'])
        else:
            # signature not present in url (line 33), need js to descramble
            # TypeError caught in __main__
            raise TypeError('JS is None')

        logger.debug(
            'finished descrambling signature for itag=%s\n%s',
            stream['itag'], pprint.pformat(
                {
                    's': stream['s'],
                    'signature': signature,
                }, indent=2,
            ),
        )
        stream_manifest[i]['url'] = url + '&sig=' + signature

How do i find this mixins py file?

@YashKarthik
Copy link

I tried @Nowbob fix but does'nt work, it says Request not defined.

@gittethis
Copy link

gittethis commented Dec 3, 2019 via email

@hbmartin
Copy link
Contributor

hbmartin commented Feb 6, 2020

@yijun-li-20
Copy link

Cannot work with the solutions in this thread
Probably because of copyright?

Mac OS Mojave, Python 3.7

@hbmartin
Copy link
Contributor

hbmartin commented Feb 9, 2020

@yijun-li-20 what url are you looking at? what version of pytube are you using?

@makesnosense
Copy link

hi, pytube3 9.6.4 get urllib.error.HTTPError: HTTP Error 403: Forbidden on this video:
https://www.youtube.com/watch?v=yEG2VTHS9yg

@aulorbe
Copy link

aulorbe commented May 5, 2020

Where is the mixins.py file in urllib3?

@amitbirajdar
Copy link

I am using Python3 and the following changes worked for me:

So, you basically study the structure of your URL. In my case since I'm working with Youtube Data API and hence a sample URL for me looked like:

https://www.googleapis.com/youtube/v3/videos?part=snippet&id=8SbUC-UaAxE&key=AIzaSyAVtcurxxUyQznBtLU5UmxqrRSENZ6gAIA

I used the urllib.parse library and then generated the above URL using the strategy below:

params = {'part':'snippet','id':VIDEO_KEY_goes_here', 'key':'YOUR_API_KEY_goes_here'}
querystring = urllib.parse.urlencode(params)
stats_url = 'https://www.googleapis.com/youtube/v3/videos'+'?'+querystring

@github-actions
Copy link

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

@cha1m
Copy link

cha1m commented Mar 25, 2021

With 9.5.1 (the latest downloaded) I tinkered with all the fixes from this thread and finally got it working. There are two separate issues that i had to tackle:

  1. KeyError:['title'] and
  2. "403: Forbidden"

1)FIrst one to solve was the KeyError:['title']
For some reason the 'title' key is not retrieved anymore in the root of the player_config_args dictionary, hence the error. Upon debugging of the req/reply I found It is instead present in "player_response/videoDetails/title", so edit main.py:

def title(self):
        #Get the video title.

        #:rtype: str

        try:
                tt1 = self.player_config_args['title']
        except:
                tt1 = self.player_config_args.get('player_response', {}).get('videoDetails', {}).get('title')
        finally:
                if not tt1:
                        tt1 = "Unknown YTube video"
        return tt1

and streams.py:

    def default_filename(self):
        """Generate filename based on the video title.

        :rtype: str
        :returns:
            An os file system compatible filename.
        """
        try:
                title = self.player_config_args['title']
        except:
                title = self.player_config_args.get('player_response', {}).get('videoDetails', {}).get('title')
        finally:
                if not title:
                        title = "Unknown YTube video"
        filename = safe_filename(title)
        return '{filename}.{s.subtype}'.format(filename=filename, s=self)

I did also apply the fix found in this thread to request.py about the Agent-User:
from urllib2 import Request
and

req = Request(url, headers = {"User-Agent": "Mozilla/5.0"})
    #response = urlopen(url)
    response = urlopen(req)

2)For the "403 Forbidden" I applied first the suggestion about mixins.py in the apply_signature function:

         if ('signature=' in url or
                ('s' not in stream and
                ('&sig=' in url or '&lsig=' in url))):

            # For certain videos, YouTube will just provide them pre-signed, in
            # which case there's no real magic to download them and we can skip
            # the whole signature descrambling entirely.
            logger.debug('signature found, skip decipher')
            continue

        if js is not None:
            signature = cipher.get_signature(js, stream['s'])
        else:
            # signature not present in url (line 33), need js to descramble
            # TypeError caught in __main__
            raise TypeError('JS is None')

        logger.debug(
            'finished descrambling signature for itag=%s\n%s',
            stream['itag'], pprint.pformat(
                {
                    's': stream['s'],
                    'signature': signature,
                }, indent=2,
            ),
        )
        stream_manifest[i]['url'] = url + '&sig=' + signature

then in the cipher.py I replaced the regex pattern as suggested in another post of this thread:

pattern = [
        r'\b[cs]\s*&&\s*[adf]\.set\([^,]+\s*,\s*encodeURIComponent\s*\(\s*(?P<sig>[a-zA-Z0-9$]+)\(',
        r'\b[a-zA-Z0-9]+\s*&&\s*[a-zA-Z0-9]+\.set\([^,]+\s*,\s*encodeURIComponent\s*\(\s*(?P<sig>[a-zA-Z0-9$]+)\(',
        r'(?P<sig>[a-zA-Z0-9$]+)\s*=\s*function\(\s*a\s*\)\s*{\s*a\s*=\s*a\.split\(\s*""\s*\)',
        r'(["\'])signature\1\s*,\s*(?P<sig>[a-zA-Z0-9$]+)\(',
        r'\.sig\|\|(?P<sig>[a-zA-Z0-9$]+)\(',
        r'yt\.akamaized\.net/\)\s*\|\|\s*.*?\s*[cs]\s*&&\s*[adf]\.set\([^,]+\s*,\s*(?:encodeURIComponent\s*\()?\s*(?P<si$',
        r'\b[cs]\s*&&\s*[adf]\.set\([^,]+\s*,\s*(?P<sig>[a-zA-Z0-9$]+)\(',
        r'\b[a-zA-Z0-9]+\s*&&\s*[a-zA-Z0-9]+\.set\([^,]+\s*,\s*(?P<sig>[a-zA-Z0-9$]+)\(',
        r'\bc\s*&&\s*a\.set\([^,]+\s*,\s*\([^)]*\)\s*\(\s*(?P<sig>[a-zA-Z0-9$]+)\(',
        r'\bc\s*&&\s*[a-zA-Z0-9]+\.set\([^,]+\s*,\s*\([^)]*\)\s*\(\s*(?P<sig>[a-zA-Z0-9$]+)\(',
        r'\bc\s*&&\s*[a-zA-Z0-9]+\.set\([^,]+\s*,\s*\([^)]*\)\s*\(\s*(?P<sig>[a-zA-Z0-9$]+)\('
    ]

any chance get your help in privet? on e mail maybe?

@fschatbot
Copy link

This issue is still persistent to this date and what's more is that the mixin.py/ciper.py files are missing. If anybody has a solution for the current date then please do help.

Here is the video I am consistently getting errors with: https://youtube.com/watch?v=56tBagXBH5A

I was suggested to switch from ANDROID to WEB but it still doesn't work!

@gxosty
Copy link

gxosty commented Sep 17, 2023

Hello. So for some reason for me HTTP Error 403 Forbidden happens when opening the same stream url twice. I have checked with pytube-cli. The first time url is getting opened when getting stream.filesize stream property to print Video Title | filesize. And the second time it requests the same url to download video. That leads to 403 Forbidden.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests