Andrej Aleksic
Andrej Aleksic

Reputation: 173

How to solve HTTP Error 400: Bad Request in PyTube?

I made a simple 3 line project with pyTube library. All it does is download a video from YT. With it I usually download videos of handball games which are around 100 minutes long. It all worked fine 7 days ago when i last used it but now it throws an "HTTP Error 400: Bad Request" error.

from pytube import YouTube

youtubeObject = YouTube('https://www.youtube.com/watch?v=DASMWPUFFP4')

youtubeObject = youtubeObject.streams.get_highest_resolution()

youtubeObject.download('D:\\Utakmice')

It works with a shorter videos but it doesnt work with any other videos of the similar length (~100mins). I tried upgrading pyTube library and cleaning browser cache but it didnt help. Tried to dig dipper into the urllib but couldnt find anything there either. The error I am getting is:

urllib.error.HTTPError: HTTP Error 400: Bad Request

Couldnt find any solution online so any help is appreciated. Thanks in advance.

EDIT-FIXED PROBLEM

I found an issue about this on the pytube GitHub. The fix requiered the change of certain client versions in innertube.py file. The link to the issue: https://github.com/pytube/pytube/issues/1894#issue-2180600881

Upvotes: 16

Views: 32206

Answers (6)

Priyanshu Dhaked
Priyanshu Dhaked

Reputation: 1

!pip install yt_dlp
import yt_dlp

ydl_opts = {}

def dwl_vid(video_url):
    with yt_dlp.YoutubeDL(ydl_opts) as ydl:
        ydl.download([video_url])

channel = 1
while channel == 1:
    link_of_the_video = input("Copy & paste the URL of the YouTube video you want to download: ")
    zxt = link_of_the_video.strip()

    dwl_vid(zxt)
    channel = int(input("Enter 1 if you want to download more videos\nEnter 0 if you are done: "))

Upvotes: 0

Stas Balazuk
Stas Balazuk

Reputation: 1

pip install tk --upgrade
pip install ctk --upgrade
pip install pytube --upgrade
pip install customtkinter --upgrade
pip install pytubefix --upgrade



import tkinter as tk
import customtkinter as ctk
from pytubefix import YouTube
from pytubefix.cli import on_progress
def download_video():
    try:
        yt_link = url_var.get()
        yt_object = YouTube(yt_link, on_progress_callback = on_progress)
        video = yt_object.streams.get_highest_resolution()
        video.download()
        print("Download Complete")
    except Exception as e:
        print(f"Invalid link{e}")
    ctk.set_appearance_mode("System")
    ctk.set_default_color_theme("blue")
    app = ctk.CTk()
    app.geometry("720x480")
    app.title("YouTube Download")
    url_var = tk.StringVar()
    title = ctk.CTkLabel(app, text="Insert a YouTube link")
    title.pack(padx=10, pady=10)
    link = ctk.CTkEntry(app, width=350, height=40, textvariable=url_var)
    link.pack()
    download = ctk.CTkButton(app, text="Download", command=download_video)
    download.pack()
app.mainloop()

Upvotes: -1

ghareeb fathy
ghareeb fathy

Reputation: 455

I tried this and it worked fine for me

pip install pytubefix

from pytubefix import YouTube
from pytubefix.cli import on_progress
 
url = "url"
 
yt = YouTube(url, on_progress_callback = on_progress)
print(yt.title)
 
ys = yt.streams.get_highest_resolution()
ys.download()

that writes the same command as the pytube library

#This is a link to the library. https://pypi.org/project/pytubefix/

Upvotes: 13

abdou_dev
abdou_dev

Reputation: 323

This is a recent issue that has been raised in the Pytube project: issue link

In the meantime, you can use a new package as suggested by Tomtunn. It serves a similar purpose named pytubefix

I hope this solves your issue

Upvotes: 13

Amine Gazit
Amine Gazit

Reputation: 11

I got the same issue and I fixed it by changing this line from innertube.py:

def __init__(self, client='ANDROID', use_oauth=False, allow_cache=True):

to this:

def __init__(self, client='WEB', use_oauth=False, allow_cache=True):

Upvotes: 1

Darkness4869
Darkness4869

Reputation: 21

Got the same error as it looks like the request sent is not a good one to YouTube Servers.

Traceback (most recent call last):

    File "/var/www/html/ytd_web_app/venv/lib/python3.10/site-packages/flask/app.py", line 2213, in __call__
    return self.wsgi_app(environ, start_response)
    File "/var/www/html/ytd_web_app/venv/lib/python3.10/site-packages/flask/app.py", line 2193, in wsgi_app
    response = self.handle_exception(e)
    File "/var/www/html/ytd_web_app/venv/lib/python3.10/site-packages/flask/app.py", line 2190, in wsgi_app
    response = self.full_dispatch_request()
    File "/var/www/html/ytd_web_app/venv/lib/python3.10/site-packages/flask/app.py", line 1486, in full_dispatch_request
    rv = self.handle_user_exception(e)
    File "/var/www/html/ytd_web_app/venv/lib/python3.10/site-packages/flask/app.py", line 1484, in full_dispatch_request
    rv = self.dispatch_request()
    File "/var/www/html/ytd_web_app/venv/lib/python3.10/site-packages/flask/app.py", line 1469, in dispatch_request
    return self.ensure_sync(self.view_functions[rule.endpoint])(**view_args)
    File "/var/www/html/ytd_web_app/Routes/Media.py", line 90, in getMedia
    file = getMetaData(file_name)
    File "/var/www/html/ytd_web_app/Routes/Media.py", line 43, in getMetaData
    response = json.dumps(media.verifyPlatform(), indent=4)
    File "/var/www/html/ytd_web_app/Models/Media.py", line 164, in verifyPlatform
    "data": self.handleYouTube()
    File "/var/www/html/ytd_web_app/Models/Media.py", line 227, in handleYouTube
    youtube = self._YouTubeDownloader.search()
    File "/var/www/html/ytd_web_app/Models/YouTubeDownloader.py", line 297, in search
    "author_channel": self.getVideo().channel_url,
    File "/var/www/html/ytd_web_app/venv/lib/python3.10/site-packages/pytube/__main__.py", line 432, in channel_url
    return f'https://www.youtube.com/channel/{self.channel_id}'
    File "/var/www/html/ytd_web_app/venv/lib/python3.10/site-packages/pytube/__main__.py", line 424, in channel_id
    return self.vid_info.get('videoDetails', {}).get('channelId', None)
    File "/var/www/html/ytd_web_app/venv/lib/python3.10/site-packages/pytube/__main__.py", line 246, in vid_info
    innertube_response = innertube.player(self.video_id)
    File "/var/www/html/ytd_web_app/venv/lib/python3.10/site-packages/pytube/innertube.py", line 448, in player
    return self._call_api(endpoint, query, self.base_data)
    File "/var/www/html/ytd_web_app/venv/lib/python3.10/site-packages/pytube/innertube.py", line 390, in _call_api
    response = request._execute_request(
    File "/var/www/html/ytd_web_app/venv/lib/python3.10/site-packages/pytube/request.py", line 37, in _execute_request
    return urlopen(request, timeout=timeout)  # nosec
    File "/usr/lib/python3.10/urllib/request.py", line 216, in urlopen
    return opener.open(url, data, timeout)
    File "/usr/lib/python3.10/urllib/request.py", line 525, in open
    response = meth(req, response)
    File "/usr/lib/python3.10/urllib/request.py", line 634, in http_response
    response = self.parent.error(
    File "/usr/lib/python3.10/urllib/request.py", line 563, in error
    return self._call_chain(*args)
    File "/usr/lib/python3.10/urllib/request.py", line 496, in _call_chain
    result = func(*args)
    File "/usr/lib/python3.10/urllib/request.py", line 643, in http_error_default
    raise HTTPError(req.full_url, code, msg, hdrs, fp)
    urllib.error.HTTPError: HTTP Error 400: Bad Request

Moreover, the error is generated as a client-side error given that the request is a POST request as when it is further and research and analysis is done it is found that PyTube is using the version 1.0 given that the YouTube's API as the latest version for that API is 3.0.

def _execute_request(
    url: str,
    method: str | None = None,
    headers: dict[str, str] | None = None,
    data: bytes | None = None,
    timeout: float = socket._GLOBAL_DEFAULT_TIMEOUT
) -> _UrlopenRet:
    """
    Executing the request from the PyTube's API towards the
    YouTube API endpoint to retrieve the Stream's data.
    
    Parameters:
        url: string: The uniform resource locator of the API endpoint.
        method: string: The HTTP request method to be used.
        headers: object: The HTTP headers to be used by the API.
        data: bytes: The data to be passed into the request.
        timeout: float: The timeout delay to close the connection.

    Returns:
        _UrlopenRet
    """
    base_headers = {"User-Agent": "Mozilla/5.0", "accept-language": "en-US,en"}
    if headers:
        base_headers.update(headers)
    if data:
        if not isinstance(data, bytes):
            data = bytes(json.dumps(data), encoding="utf-8")
    if url.lower().startswith("http"):
        request = Request(url, headers=base_headers, method=method, data=data)
    else:
        raise ValueError("Invalid URL")
    return urlopen(request, timeout=timeout)
def _call_api(self, endpoint: str, query: list[str], data: bytes):
    """
    Generating the request to a given endpoint withe the
    provided query parameters and data.

    Parameters:
        endpoint: string: The uniform resource locator of the endpoint to the YouTube's API.
        query: array: The HTTP query to be sent to the API.
        data: bytes: The data to be passed into the request.
    """
    if self.use_oauth:
        del query['key']
    endpoint_url = f'{endpoint}?{parse.urlencode(query)}'
    headers = {
        'Content-Type': 'application/json',
    }
    if self.use_oauth:
        if self.access_token:
            self.refresh_bearer_token()
            headers['Authorization'] = f'Bearer {self.access_token}'
        else:
            self.fetch_bearer_token()
            headers['Authorization'] = f'Bearer {self.access_token}'
    headers.update(self.header)
    response = request._execute_request(
        endpoint_url,
        'POST',
        headers=headers,
        data=data
    )
    return json.loads(response.read())
def player(self, video_id: str) -> dict:
    """
    Making the request to the player endpoint.
    
    Parameters:
        video_id: string: The identifier of the video to get the player data for.

    Returns:
        object
    """
    endpoint = f'{self.base_url}/player'
    query = {
        'videoId': video_id,
    }
    query.update(self.base_params)
    return self._call_api(endpoint, query, self.base_data)
@property
def base_url(self) -> str:
    """
    Returning the base uniform resource locator endpoint for the
    InnerTube API.

    Returns:
        string
    """
    return 'https://www.youtube.com/youtubei/v1'

Upvotes: 2

Related Questions