0
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?

yt-dlpでYouTubeから音声を抽出してAI音源分離する完全ガイド:Python実装【2026年版】

0
Posted at

YouTubeから音声を抽出してDAWやPython処理に持ち込みたい場面、よくありますよね。「カバーする曲のオフボーカルが欲しい」「BGM素材として使いたい」「自分が以前アップした動画の音だけ取り出したい」――。

この記事では、yt-dlp(現在のYouTube音声抽出のデファクトスタンダード)とDemucs(AI音源分離)を組み合わせて、URL を投げると → 音声抽出 → ボーカル / 伴奏 / ドラム / ベースに分離まで全自動で行うPythonパイプラインを作ります。

法的な注意(必読):YouTubeの利用規約 第5条は、ダウンロードボタンが提供されていない動画のダウンロードを原則禁止しています。日本の著作権法 第30条(私的使用のための複製)は限定的に適用される可能性がありますが、技術的保護手段の回避や再配布はカバーされません。本記事は以下のいずれかに該当するケースのみを前提としています:

  • 自分自身がアップロードした動画
  • クリエイティブ・コモンズ等で明示的にダウンロード許諾された動画
  • パブリックドメインの動画

商用利用や再配布を伴う場合は、必ず権利者の許諾を取得してください。

この記事でわかること

  • ✅ yt-dlp の最新版インストール方法(Mac/Windows/Linux)
  • ✅ YouTube動画から最高音質の音声だけを抽出する方法
  • ✅ 抽出した音声をDemucsでボーカル / 伴奏に分離する方法
  • ✅ URL → 分離済みステムまでを1コマンドで実行するPythonパイプライン
  • ✅ プレイリスト一括処理 / よくあるエラー(HTTP 403、署名失敗)の対処
  • ✅ ノーコード/APIで済ませる選択肢

全体パイプライン

YouTube URL
   ↓ yt-dlp(音声抽出)
audio.m4a / audio.opus
   ↓ ffmpeg(必要なら mp3 / wav 変換)
audio.wav
   ↓ Demucs(AI音源分離)
   ├─ vocals.wav    (ボーカルのみ)
   ├─ drums.wav
   ├─ bass.wav
   └─ other.wav     (その他楽器)

前提条件

  • Python 3.10以上
  • ffmpeg(音声フォーマット変換に必須)
  • ストレージ:1曲あたり50〜200MB程度の作業領域
pip install yt-dlp demucs torch torchaudio soundfile requests

ステップ1:yt-dlpをインストールする

結論pip install -U yt-dlp がもっとも簡単で、すべてのOSで動きます。

yt-dlp は1日に1〜2回更新されることがあり、YouTube側の仕様変更にすぐ追随します。古いバージョンだと「signature extraction failed」「HTTP Error 403」が頻発するので、定期的に最新版に上げる前提で運用してください。

# 全OS共通:pip経由(推奨)
pip install -U yt-dlp

# macOS(Homebrew)
brew install yt-dlp

# Windows(winget)
winget install yt-dlp.yt-dlp

# Linux(バイナリ直接)
sudo curl -L https://github.com/yt-dlp/yt-dlp/releases/latest/download/yt-dlp -o /usr/local/bin/yt-dlp
sudo chmod a+rx /usr/local/bin/yt-dlp

ffmpeg も必須です。

brew install ffmpeg              # macOS
sudo apt install ffmpeg          # Ubuntu
winget install Gyan.FFmpeg       # Windows

yt-dlp と youtube-dl の違いは?

結論:2026年現在、選ぶべきは yt-dlp です。

youtube-dl は2020年以降ほぼメンテナンスが止まっており、現在のYouTubeの仕様変更にほとんど追随できていません。yt-dlp は youtube-dl の活発な fork で、毎日更新があり、抽出フォーマット数も youtube-dl の数倍です。Pythonコードでも import yt_dlp の形でほぼ youtube-dl 互換APIで使えます。


ステップ2:YouTubeから音声だけを抽出する

結論yt-dlp -f bestaudio --extract-audio --audio-format wav <URL> で最高音質の音声だけが落ちてきます。

CLIで一発抽出する場合:

yt-dlp \
  -f bestaudio \
  --extract-audio \
  --audio-format wav \
  --audio-quality 0 \
  -o "downloads/%(title)s.%(ext)s" \
  "https://www.youtube.com/watch?v=XXXXXXXXXXX"

オプションの意味:

フラグ 効果
-f bestaudio 利用可能な音声ストリームのうち最高ビットレートを選択
--extract-audio 動画コンテナから音声トラックだけを取り出す
--audio-format wav 出力フォーマット(wav / mp3 / m4a / opus / flac)
--audio-quality 0 0が最高品質(mp3変換時は約 320kbps)
-o 出力ファイル名のテンプレート

Pythonからプログラム的に呼ぶ場合

CLIでもいいのですが、後段のDemucsとつなげるならPython APIが圧倒的に楽です。

# step1_extract.py
from pathlib import Path
import yt_dlp


def download_audio(url: str, out_dir: str = "downloads") -> Path:
    """
    YouTube URL → wav ファイルへ抽出する。返り値は出力ファイルパス。
    """
    Path(out_dir).mkdir(exist_ok=True)
    opts = {
        "format": "bestaudio/best",
        "outtmpl": f"{out_dir}/%(id)s.%(ext)s",
        "postprocessors": [
            {
                "key": "FFmpegExtractAudio",
                "preferredcodec": "wav",
                "preferredquality": "0",
            }
        ],
        "quiet": True,
        "no_warnings": True,
    }
    with yt_dlp.YoutubeDL(opts) as ydl:
        info = ydl.extract_info(url, download=True)
        return Path(out_dir) / f"{info['id']}.wav"


if __name__ == "__main__":
    out = download_audio("https://www.youtube.com/watch?v=YOUR_VIDEO_ID")
    print(f"抽出完了: {out}")

ポイント:outtmpl%(id)s.%(ext)s にすると、動画ID(11文字の英数字)でファイル名が固定されるので、後段の処理でファイルパスが予測可能になります。詳しい音声抽出パターンは別解説のYouTube音声抽出ガイドも参考になります。


ステップ3:抽出した音声をDemucsで分離する

結論htdemucs_ft モデルを使えば、4分の楽曲を約1〜3分でボーカル / ドラム / ベース / その他の4トラックに分離できます。

Demucs はMeta(旧FAIR)が公開している音源分離モデルで、現在のオープンソース最高峰です。htdemucs_ft は標準モデルをファインチューニングしたバージョンで、ボーカル分離精度がワンランク上がります。

# step2_separate.py
import subprocess
from pathlib import Path


def separate(audio_path: Path, out_dir: str = "stems") -> dict[str, Path]:
    """
    音声ファイル → 4-stem(vocals/drums/bass/other)に分離する。
    """
    Path(out_dir).mkdir(exist_ok=True)
    subprocess.run(
        ["demucs", "-n", "htdemucs_ft", "-o", out_dir, str(audio_path)],
        check=True,
    )
    base = Path(out_dir) / "htdemucs_ft" / audio_path.stem
    return {
        "vocals": base / "vocals.wav",
        "drums":  base / "drums.wav",
        "bass":   base / "bass.wav",
        "other":  base / "other.wav",
    }

ボーカルだけ欲しい / オフボーカルだけ欲しい場合

4分割は不要で、「ボーカル」と「それ以外」の2トラックだけが欲しい場合は --two-stems オプションが速いです(処理時間ほぼ半分)。

subprocess.run([
    "demucs",
    "--two-stems", "vocals",
    "-n", "htdemucs_ft",
    "-o", "stems",
    str(audio_path),
], check=True)
# → stems/htdemucs_ft/<id>/vocals.wav と no_vocals.wav が出力

YouTubeステム分離の仕組みで精度ベンチマークを詳しく解説しています。


ステップ4:URL → ステム分離まで全自動化する

ステップ1とステップ2をつなげて、URL を渡すだけで4トラックに分離されたWAVが返ってくる関数にします。

# pipeline.py
from pathlib import Path
from step1_extract import download_audio
from step2_separate import separate


def youtube_to_stems(url: str, work_dir: str = "work") -> dict[str, Path]:
    """
    YouTube URL → 4-stem WAV ファイル一式 のフルパイプライン。
    """
    work = Path(work_dir)
    work.mkdir(exist_ok=True)

    print(f"[1/2] YouTubeから音声を抽出中: {url}")
    audio = download_audio(url, out_dir=str(work / "downloads"))
    print(f"{audio}")

    print(f"[2/2] AI音源分離中(htdemucs_ft)...")
    stems = separate(audio, out_dir=str(work / "stems"))
    for part, path in stems.items():
        print(f"{part}: {path}")
    return stems


if __name__ == "__main__":
    import sys
    url = sys.argv[1] if len(sys.argv) > 1 else input("YouTube URL: ")
    youtube_to_stems(url)

実行例:

$ python pipeline.py "https://www.youtube.com/watch?v=YOUR_VIDEO_ID"
[1/2] YouTubeから音声を抽出中: https://www.youtube.com/watch?v=YOUR_VIDEO_ID
      → work/downloads/YOUR_VIDEO_ID.wav
[2/2] AI音源分離中(htdemucs_ft)...
      → vocals: work/stems/htdemucs_ft/YOUR_VIDEO_ID/vocals.wav
      → drums:  work/stems/htdemucs_ft/YOUR_VIDEO_ID/drums.wav
      → bass:   work/stems/htdemucs_ft/YOUR_VIDEO_ID/bass.wav
      → other:  work/stems/htdemucs_ft/YOUR_VIDEO_ID/other.wav

実測時間(4分の楽曲):

マシン 抽出(yt-dlp) 分離(Demucs) 合計
MacBook Air M2 約8秒 約45秒 約53秒
Intel i7(GPU無し) 約8秒 約3分30秒 約3分40秒
RTX 3060 (12GB) 約8秒 約12秒 約20秒

プレイリストを一括処理する

「プレイリストの全曲をオフボーカルにしたい」という場合は、yt-dlpがプレイリスト展開を自動でやってくれます。

# batch.py
from pathlib import Path
import yt_dlp
from step2_separate import separate


def download_playlist(playlist_url: str, out_dir: str = "downloads") -> list[Path]:
    Path(out_dir).mkdir(exist_ok=True)
    opts = {
        "format": "bestaudio/best",
        "outtmpl": f"{out_dir}/%(playlist_index)02d_%(id)s.%(ext)s",
        "postprocessors": [
            {"key": "FFmpegExtractAudio", "preferredcodec": "wav", "preferredquality": "0"}
        ],
        "ignoreerrors": True,
        "quiet": True,
    }
    files: list[Path] = []
    with yt_dlp.YoutubeDL(opts) as ydl:
        info = ydl.extract_info(playlist_url, download=True)
        for entry in info.get("entries", []):
            if entry is None:
                continue
            files.append(
                Path(out_dir) / f"{entry['playlist_index']:02d}_{entry['id']}.wav"
            )
    return files


def batch_separate(playlist_url: str) -> None:
    audios = download_playlist(playlist_url)
    print(f"{len(audios)} 曲ダウンロード完了")
    for i, audio in enumerate(audios, 1):
        print(f"[{i}/{len(audios)}] 分離中: {audio.name}")
        separate(audio)

ignoreerrors=True を付けておくと、削除された動画や非公開動画があってもそこで止まらず続行します。


ノーコード/APIで完結させたい場合

「Pythonで毎回コマンドを叩くより、URLをWebに投げるだけで結果のZIPが落ちてくる方が楽」というケース向けに、StemSplitのYouTubeステム分離ツールを使う手もあります。内部はHTDemucsベースで、本記事のローカル版と同等の品質が出ます。GPU不要で、CIやServerlessから叩きたい場合にも便利です。

API経由ならローカルに依存ライブラリを入れる必要もありません:

import os, time, requests
HEADERS = {"Authorization": f"Bearer {os.environ['STEMSPLIT_API_KEY']}"}

def youtube_to_stems_api(url: str) -> dict:
    job = requests.post(
        "https://api.stemsplit.io/v1/jobs",
        headers=HEADERS,
        json={"youtube_url": url, "stems": "4"},
    ).json()
    while True:
        status = requests.get(
            f"https://api.stemsplit.io/v1/jobs/{job['job_id']}", headers=HEADERS,
        ).json()
        if status["status"] == "completed":
            return status["stems"]
        if status["status"] == "failed":
            raise RuntimeError(status.get("error"))
        time.sleep(3)

応用1:歌ってみた用のオフボーカル化

ステップ3で出力された no_vocals.wav がそのままオフボーカル音源になります。歌ってみたへの活用方法(音圧調整・サビでボーカルが残る問題の対処など)は別記事に詳しくまとめています。

歌ってみた用のオフボーカル音源をPythonで自作する方法【AI音源分離・2026年版】

応用2:VTuber歌枠のセトリ準備

セトリの全曲をYouTubeから直接ダウンロード→分離→配信ラウドネス(-16 LUFS)に整えるところまでを自動化したい場合:

VTuberの歌枠配信用カラオケ音源を5分で量産するPythonスクリプト【AI音源分離】

応用3:歌詞付きカラオケ動画化

抽出した音声からWhisperで歌詞も起こせば、「歌詞付きカラオケ動画(mp4)」まで自動生成できます。

自分専用カラオケ動画をPythonで作る:AI音源分離 × Whisper × 歌詞同期の完全ガイド【2026年版】


よくあるエラーと対処

エラー 原因 対処
HTTP Error 403: Forbidden yt-dlpが古い/YouTubeの仕様変更 pip install -U yt-dlp で最新版に更新
ERROR: Signature extraction failed 同上 同上、または --no-check-certificate を試す
ffmpeg not found ffmpeg未インストール OSごとのパッケージマネージャでインストール
Video unavailable 地域制限/削除/非公開 別の動画でテスト、--cookies-from-browser でログイン情報を渡す
Premieres in N minutes プレミア公開待ち 公開後に再実行
Demucsで CUDA out of memory VRAM不足 --device cpu でCPU実行、または --segment 7 で分割推論
出力WAVがモノラルになる 元動画がモノラル音声 元素材の問題。回避不可

特に HTTP 403Signature extraction failedyt-dlpを更新するだけで直ることがほとんどです。本番運用では pip install -U yt-dlp を週1のcronに入れておくと安心です。


関連記事


まとめ

  • yt-dlp + Demucs の組み合わせで、YouTube URL → 4-stem WAV までのフルパイプラインがPython 50行で組めます
  • yt-dlpは頻繁に更新されるので pip install -U yt-dlp を定期実行する運用を推奨します
  • bestaudio フォーマット選択 + --audio-quality 0 で原音に最も近い品質が抽出できます
  • ローカル処理が重い場合はStemSplitのYouTubeステム分離ツールでAPI完結も可能
  • 法的注意:自分の動画/許諾済みコンテンツ/パブリックドメインのみが対象。著作権物の無断ダウンロードは違法になり得ます

YouTubeから音声を取り出して何かをやる作業、一度パイプラインを組んでおくと「URLを投げるだけで終わる」状態になります。コードはすべてコピペで動くようにしてあります。

参考リンク

0
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
0
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?