以前若要從 Youtube 擷取音訊為 mp3 檔最快的方法是將 YT 影片網址中的 ube 去掉就可透過 https://yout.com 提供的線上服務直接下載 mp3 檔, 但是該服務目前對於未註冊用戶限制每天只能下載一個 mp3, 超不方便, 參考 :
最近在讀市圖借的 "ChatGPT 網路行銷" 這本書時得知 pytube 這套件, 可用來下載 YouTube 影片, 音訊, 或者取得影片資訊, 並且可選擇不同的解析度或格式. 不過初步測試發現用 pytube 下載音訊時會出現錯誤.
詢問 ChatGPT 原因是 YouTube 的網頁結構經常變動 (特別是影片串流資料的 player_response JSON), 導致 pytube 無法解析而失敗. 解決方案是改用 fork 版的 pytubefix 套件, 因為此套件有在持續修正 YouTube 更新所造成的串流解析錯誤.
剛好岳母練歌要我幫她抓幾首歌, 就拿來當練習吧!
# https://www.youtube.com/watch?v=AgAWXdG_ck0 (蔡淳佳-陪我看日出)
# https://www.youtube.com/watch?v=CeRIWoVkgyk (夏川里美-淚光閃閃)
# https://www.youtube.com/watch?v=p4YkHQrPt2I (黃鶯鶯-哭砂)
# https://www.youtube.com/watch?v=7N0tuuS28E0 (童麗-煙花三月)
# https://www.youtube.com/watch?v=yYwn8k502qY (許美靜-城裡的月光)
# https://www.youtube.com/watch?v=7wvNwOPprBE (丁噹-手掌心)
# https://www.youtube.com/watch?v=Z8uUtPWOZ8s (陳瑞-夢醉西樓)
# https://www.youtube.com/watch?v=RIYDDWnE8rU (孫露-黃玫瑰)
# https://www.youtube.com/watch?v=Z5Xg2mBF9bA (陳瑞-玫瑰花又開)
# https://www.youtube.com/watch?v=1_A3EggDsdo (祈瑞-醉相思)
# https://www.youtube.com/watch?v=fBa6J5mIzrQ (江淑娜-庭院深深)
# https://www.youtube.com/watch?v=PMoN1djgIeA (邱廉欽-行過)
# https://www.youtube.com/watch?v=tl73EvAaCfY (楊銀花-靚靚月光)
# https://www.youtube.com/watch?v=kU53MypiPGg (羅筱蕓-半山遙)
# https://www.youtube.com/watch?v=0MobBs0kCqw (李心慈-童年夢)
首先用 pip 安裝 pytubefix 套件 :
pip install pytubefix
D:\python\test>pip install pytubefix
D:\python\test>pip install pytubefix
Collecting pytubefix
Downloading pytubefix-10.2.1-py3-none-any.whl.metadata (9.2 kB)
Collecting aiohttp>=3.12.13 (from pytubefix)
Downloading aiohttp-3.13.2-cp310-cp310-win_amd64.whl.metadata (8.4 kB)
Collecting nodejs-wheel-binaries>=22.20.0 (from pytubefix)
Downloading nodejs_wheel_binaries-22.20.0-py2.py3-none-win_amd64.whl.metadata (4.6 kB)
Collecting aiohappyeyeballs>=2.5.0 (from aiohttp>=3.12.13->pytubefix)
Downloading aiohappyeyeballs-2.6.1-py3-none-any.whl.metadata (5.9 kB)
Collecting aiosignal>=1.4.0 (from aiohttp>=3.12.13->pytubefix)
Downloading aiosignal-1.4.0-py3-none-any.whl.metadata (3.7 kB)
Requirement already satisfied: async-timeout<6.0,>=4.0 in c:\users\tony1\appdata\roaming\python\python310\site-packages (from aiohttp>=3.12.13->pytubefix) (4.0.3)
Requirement already satisfied: attrs>=17.3.0 in c:\users\tony1\appdata\roaming\python\python310\site-packages (from aiohttp>=3.12.13->pytubefix) (23.1.0)
Requirement already satisfied: frozenlist>=1.1.1 in c:\users\tony1\appdata\roaming\python\python310\site-packages (from aiohttp>=3.12.13->pytubefix) (1.4.1)
Requirement already satisfied: multidict<7.0,>=4.5 in c:\users\tony1\appdata\roaming\python\python310\site-packages (from aiohttp>=3.12.13->pytubefix) (6.0.4)
Collecting propcache>=0.2.0 (from aiohttp>=3.12.13->pytubefix)
Downloading propcache-0.4.1-cp310-cp310-win_amd64.whl.metadata (14 kB)
Collecting yarl<2.0,>=1.17.0 (from aiohttp>=3.12.13->pytubefix)
Downloading yarl-1.22.0-cp310-cp310-win_amd64.whl.metadata (77 kB)
Requirement already satisfied: idna>=2.0 in c:\users\tony1\appdata\roaming\python\python310\site-packages (from yarl<2.0,>=1.17.0->aiohttp>=3.12.13->pytubefix) (3.4)
Requirement already satisfied: typing-extensions>=4.2 in c:\users\tony1\appdata\local\programs\thonny\lib\site-packages (from aiosignal>=1.4.0->aiohttp>=3.12.13->pytubefix) (4.12.2)
Downloading pytubefix-10.2.1-py3-none-any.whl (1.5 MB)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 1.5/1.5 MB 3.6 MB/s eta 0:00:00
Downloading aiohttp-3.13.2-cp310-cp310-win_amd64.whl (455 kB)
Downloading yarl-1.22.0-cp310-cp310-win_amd64.whl (86 kB)
Downloading aiohappyeyeballs-2.6.1-py3-none-any.whl (15 kB)
Downloading aiosignal-1.4.0-py3-none-any.whl (7.5 kB)
Downloading nodejs_wheel_binaries-22.20.0-py2.py3-none-win_amd64.whl (40.1 MB)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 40.1/40.1 MB 9.9 MB/s eta 0:00:00
Downloading propcache-0.4.1-cp310-cp310-win_amd64.whl (41 kB)
Installing collected packages: propcache, nodejs-wheel-binaries, aiosignal, aiohappyeyeballs, yarl, aiohttp, pytubefix
Attempting uninstall: aiosignal
Found existing installation: aiosignal 1.3.1
Uninstalling aiosignal-1.3.1:
Successfully uninstalled aiosignal-1.3.1
Attempting uninstall: yarl
Found existing installation: yarl 1.9.4
Uninstalling yarl-1.9.4:
Successfully uninstalled yarl-1.9.4
Attempting uninstall: aiohttp
Found existing installation: aiohttp 3.9.1
Uninstalling aiohttp-3.9.1:
Successfully uninstalled aiohttp-3.9.1
ERROR: pip's dependency resolver does not currently take into account all the packages that are installed. This behaviour is the source of the following dependency conflicts.
line-bot-sdk 3.7.0 requires aiohttp==3.9.1, but you have aiohttp 3.13.2 which is incompatible.
line-bot-sdk 3.7.0 requires urllib3<3,>=2.0.5, but you have urllib3 1.26.19 which is incompatible.
finmind 1.6.9 requires ta~=0.5.25, but you have ta 0.11.0 which is incompatible.
Successfully installed aiohappyeyeballs-2.6.1 aiohttp-3.13.2 aiosignal-1.4.0 nodejs-wheel-binaries-22.20.0 propcache-0.4.1 pytubefix-10.2.1 yarl-1.22.0
請注意, pytubefix 依賴的 aiohttp 3.13.2 與 line-bot-sdk 的 aiohttp 3.9.1 版衝突, 後續要測試看看 LINE Bot 會不會受影響.
匯入 pytude.YouTube 類別, 呼叫其建構式並傳入 Youtube 影片網址 (例如夏川里美的淚光閃閃) 建立 YouTube 物件 :
>>> from pytube import YouTube
>>> url='ttps://www.youtube.com/watch?v=CeRIWoVkgyk'
>>> yt=YouTube(url)
>>> type(yt)
<class 'pytube.__main__.YouTube'>
然後用下列指令從影片可用的所有串流中過濾出音訊串流 (挑出第一個純音訊串流), 這會傳回一個 Stream 物件 :
>>> audio_stream=yt.streams.filter(only_audio=True).first()
>>> type(audio_stream)
<class 'pytubefix.streams.Stream'>
呼叫 Stream 物件的 downlowd() 方法即可下載音訊 (mp4 影片的音訊為 m4a 檔案格式) :
>>> audio_stream.download()
'D:\\python\\test\\夏川里美 淚そうそう ( 淚光閃閃).m4a'
用 Windows 的 Media Player 即可播放 m4a 檔案, 但舊款車載音響或播放器可能不支援 m4a, 可以用 ffmpeg 軟體轉成 mp3, 參考 :
將 .m4a 檔案轉成 .mp3 檔的轉換指令如下 :
ffmpeg -i input.m4a output.mp3
上面所下載的 m4a 檔名含有空格, ffmpeg 會無法處理, 所以先將其改為 "夏川里美-淚光閃閃.m4a" 再轉換, 指令如下 :
ffmpeg -i 夏川里美-淚光閃閃.m4a 夏川里美-淚光閃閃.mp3
D:\python\test>ffmpeg -i 夏川里美-淚光閃閃.m4a 夏川里美-淚光閃閃.mp3
ffmpeg version 2025-11-02-git-f5eb11a71d-essentials_build-www.gyan.dev Copyright (c) 2000-2025 the FFmpeg developers
built with gcc 15.2.0 (Rev8, Built by MSYS2 project)
configuration: --enable-gpl --enable-version3 --enable-static --disable-w32threads --disable-autodetect --enable-cairo --enable-fontconfig --enable-iconv --enable-gnutls --enable-libxml2 --enable-gmp --enable-bzlib --enable-lzma --enable-zlib --enable-libsrt --enable-libssh --enable-libzmq --enable-avisynth --enable-sdl2 --enable-libwebp --enable-libx264 --enable-libx265 --enable-libxvid --enable-libaom --enable-libopenjpeg --enable-libvpx --enable-mediafoundation --enable-libass --enable-libfreetype --enable-libfribidi --enable-libharfbuzz --enable-libvidstab --enable-libvmaf --enable-libzimg --enable-amf --enable-cuda-llvm --enable-cuvid --enable-dxva2 --enable-d3d11va --enable-d3d12va --enable-ffnvcodec --enable-libvpl --enable-nvdec --enable-nvenc --enable-vaapi --enable-openal --enable-libgme --enable-libopenmpt --enable-libopencore-amrwb --enable-libmp3lame --enable-libtheora --enable-libvo-amrwbenc --enable-libgsm --enable-libopencore-amrnb --enable-libopus --enable-libspeex --enable-libvorbis --enable-librubberband
libavutil 60. 16.100 / 60. 16.100
libavcodec 62. 19.100 / 62. 19.100
libavformat 62. 6.101 / 62. 6.101
libavdevice 62. 2.100 / 62. 2.100
libavfilter 11. 9.100 / 11. 9.100
libswscale 9. 3.100 / 9. 3.100
libswresample 6. 2.100 / 6. 2.100
Input #0, mov,mp4,m4a,3gp,3g2,mj2, from '夏川里美-淚光閃閃.m4a':
Metadata:
major_brand : dash
minor_version : 0
compatible_brands: iso6mp41
creation_time : 2024-04-30T04:26:11.000000Z
encoder : Google
Duration: 00:04:18.72, start: 0.000000, bitrate: 48 kb/s
Stream #0:0[0x1](eng): Audio: aac (HE-AAC) (mp4a / 0x6134706D), 44100 Hz, stereo, fltp, 48 kb/s (default)
Metadata:
creation_time : 2024-04-30T04:26:11.000000Z
handler_name : ISO Media file produced by Google Inc.
vendor_id : [0][0][0][0]
Stream mapping:
Stream #0:0 -> #0:0 (aac (native) -> mp3 (libmp3lame))
Press [q] to stop, [?] for help
Output #0, mp3, to '夏川里美-淚光閃閃.mp3':
Metadata:
major_brand : dash
minor_version : 0
compatible_brands: iso6mp41
TSSE : Lavf62.6.101
Stream #0:0(eng): Audio: mp3, 44100 Hz, stereo, fltp (default)
Metadata:
encoder : Lavc62.19.100 libmp3lame
creation_time : 2024-04-30T04:26:11.000000Z
handler_name : ISO Media file produced by Google Inc.
vendor_id : [0][0][0][0]
[out#0/mp3 @ 0000019b3b488f40] video:0KiB audio:4043KiB subtitle:0KiB other streams:0KiB global headers:0KiB muxing overhead: 0.008334%
size= 4043KiB time=00:04:18.71 bitrate= 128.0kbits/s speed=66.7x elapsed=0:00:03.88
不過 mp3 檔案大小通常會比 m4a 大一些 :
D:\python\test>dir 夏川里美-淚光閃閃.*
磁碟區 D 中的磁碟是 新增磁碟區
磁碟區序號: 1258-16B8
D:\python\test 的目錄
2025/11/10 下午 08:38 1,578,364 夏川里美-淚光閃閃.m4a
2025/11/10 下午 09:13 4,140,230 夏川里美-淚光閃閃.mp3
2 個檔案 5,718,594 位元組
注意, 雖然將 .m4a 副檔名改成 .mp3 在 PC 上仍可播放, 但其編碼格式仍是 m4a, 拿到只能播放 mp3 的舊款播放器上還是不行的.
完整的程式碼如下 :
# get_yt_audio.py
import sys
from pytubefix import YouTube
def download_audio(url, path='.'):
"""從 YouTube 下載音訊 (m4a 檔案)"""
try:
yt=YouTube(url)
print(f'下載音訊:{yt.title}')
# 取得音訊串流
audio_stream=yt.streams.filter(only_audio=True).first()
if audio_stream is None:
print('找不到可用的音訊串流!')
return
file_path=audio_stream.download(output_path=path)
print(f'音訊已下載為 m4a 檔:{file_path}\n')
except Exception as e:
print(f'下載失敗:{e}')
if __name__ == '__main__':
if len(sys.argv) < 2:
print('使用方法:python get_yt_audio.py <video_id> [download_path]')
sys.exit(1)
video_id=sys.argv[1]
path=sys.argv[2] if len(sys.argv) >= 3 else '.'
video_url=f'https://www.youtube.com/watch?v={video_id}'
download_audio(video_url, path)
此程式從命令列輸入兩個參數, 第一個是必要的 YT 影片 ID, 就是網址 "https://www.youtube.com/watch?v=" 後面的影片編號, 第二個參數是可有可無的儲存音檔之路徑, 預設是目前工作路徑, 執行結果如下 :
D:\python\test>python get_yt_audio.py DkiVWdJampQ
下載音訊:高勝美 ~ 晚風
音訊已下載為 m4a 檔:D:\python\test\高勝美 ~ 晚風.m4a
D:\python\test>python get_yt_audio.py AgAWXdG_ck0
下載音訊:陪 我 看 日 出 (蔡淳佳)《原曲 : 淚光閃閃 / 原唱 : 夏川里美》(4K 5.1聲道)
音訊已下載為 m4a 檔:D:\python\test\陪 我 看 日 出 (蔡淳佳)《原曲 淚光閃閃 原唱 夏川里美》(4K 5.1聲道).m4a
D:\python\test>python get_yt_audio.py p4YkHQrPt2I
下載音訊:黃鶯鶯 Tracy Huang - 哭砂 Cry Sand (official官方完整版MV)
音訊已下載為 m4a 檔:D:\python\test\黃鶯鶯 Tracy Huang - 哭砂 Cry Sand (official官方完整版MV).m4a
... (略) ...
用 ffmpeg 轉成 mp3 檔後, 再用 Mp3Gain 將音量一律改成 94, 最後用 Mp3tag 修改 Title 與 Author 欄位即大功告成啦! 參考 :
沒有留言 :
張貼留言