PyTubeでのHTTPエラー400: バッドリクエストの解決法
問題の概要
PythonのPyTubeライブラリを使用してYouTube動画をダウンロードする際、HTTP Error 400: Bad Requestが発生する問題があります。このエラーは以下の特徴を持っています:
- 1週間前までは正常に動作していたコードが突然エラーを出す
- 約100分程度の長い動画で発生する
- 短い動画のダウンロードでは問題ない
- エラーメッセージは
urllib.error.HTTPError: HTTP Error 400: Bad Request
- PyTubeのアップグレード/ブラウザキャッシュクリアでは解決しない
# 問題が発生する典型的なコード例
from pytube import YouTube
youtubeObject = YouTube('https://www.youtube.com/watch?v=DASMWPUFFP4')
youtubeObject = youtubeObject.streams.get_highest_resolution()
youtubeObject.download('D:\\Utakmice')
根本原因
この問題はYouTubeがAPIの変更を実施したことに起因しており、PyTubeが送信するリクエスト形式がYouTubeサーバーから「不正なリクエスト」と判定されることで発生します。PyTubeプロジェクトのGitHubイシュー #1894で詳細が議論されています。
効果的な解決策
方法1: PyTubeFixライブラリへの移推奨) PyTubeFixライブラリへの移行 (最
オリジナルのPyTubeがメンテナンスされていない状況に対応したフォーク版pytubefix
を使用します。この方法は現在最も安定した解決策です。
# インストールコマンド
pip uninstall pytube # 既存PyTubeをアンインストール
pip install pytubefix
# pytubefixの基本的な使用方法
from pytubefix import YouTube
from pytubefix.cli import on_progress
url = "https://www.youtube.com/watch?v=DASMWPUFFP4"
yt = YouTube(url, on_progress_callback=on_progress)
print(f"ダウンロード中: {yt.title}")
ys = yt.streams.get_highest_resolution()
ys.download(output_path='D:\\Utakmice')
メリット
- オリジナルのPyTubeとほぼ同じAPIインターフェース
- 長い動画のダウンロード問題を根本的に解決
- プログレスバー機能が標準装備
- PyTubeとの互換性が高いため既存コードの書き換えが最小限
方法2: innertube.pyファイルの直接修正
環境上の理由でライブラリ変更が難しい場合、PyTube内部ファイルを直接修正します。
以下のパスにある
innertube.py
を開く:your_python_path/site-packages/pytube/innertube.py
クライアント設定を変更:
# 修正前 (約109行目)
def __init__(self, client='ANDROID', use_oauth=False, allow_cache=True):
# 修正後
def __init__(self, client='WEB', use_oauth=False, allow_cache=True):
- ファイルを保存後、Python環境を再起動
注意点
この修正は一時的な対応であり、YouTubeがさらにAPIを変更すると再び動作しなくなる可能性があります。恒久的な解決策としてはpytubefix
への移行が推奨されます。
方法3: yt-dlpの使用 (代替ライブラリ)
FFmpegとの連携が必要な場合や高度なダウンロード機能が必要な場合はyt-dlp
が優れた選択肢です。
# インストール
pip install yt_dlp
import yt_dlp
def download_video(url):
ydl_opts = {
'outtmpl': 'D:/Utakmice/%(title)s.%(ext)s', # 保存パス設定
'progress_hooks': [my_hook], # オプション: 進捗表示用フック
}
with yt_dlp.YoutubeDL(ydl_opts) as ydl:
ydl.download([url])
# 進捗表示用フック関数(省略可)
def my_hook(d):
if d['status'] == 'downloading':
print(f"ダウンロード中: {d['_percent_str']}")
# 実行例
download_video('https://www.youtube.com/watch?v=DASMWPUFFP4')
各種方法の比較
解決策 | 実装の容易さ | 長期的安定性 | 追加機能 |
---|---|---|---|
pytubefix移行 | ★★★ | ★★★ | プログレス表示 |
innertpy.py修正 | ★★ | ★ | なし |
yt-dlp使用 | ★★ | ★★★ | フォーマット選択/再エンコード |
今後の予防策
YouTubeは定期的にAPI変更を行うため、以下の対策を推奨します:
ライブラリの定期的アップデート
bashpip install pytubefix --upgrade
エラーログの監視 - PyTubeの例外処理を強化
pythontry: ys.download() except Exception as e: print(f"エラー発生: {e}") # 通知処理や代替方法の実行をここに追加
代替手段の準備 - 主要機能はyt-dlpなどの代替ライブラリでも実装可能にしておく
これらの対策により、YouTubeのAPI変更が発生した場合でも迅速に対応できる体制を整えておくことが重要です。