下載 Youtube 影片 ( mp4、mp3、字幕 )
這篇文章會介紹使用 Python 的 pytube 第三方函式庫,輸入 Youtube 網址後就會自動下載為影片檔 mp4,單純下載為聲音檔 mp3,甚至可以進一步下載有字幕影片的字幕,儲存為 srt 或 txt。
快速導覽:
本篇使用的 Python 版本為 3.7.12,所有範例可使用 Google Colab 實作,不用安裝任何軟體 ( 參考:使用 Google Colab )
安裝 pytube
輸入下列指令,安裝 pytube ( 根據個人環境使用 pip、pip3 )
!pip install pytube
注意,原本 pytube 可以正常使用,但因為 Youtube API 更新安全性原則,所以原本程式碼都需要加入下面這段 ssl,不然就會拋出錯誤訊息:
import ssl
ssl._create_default_https_context = ssl._create_stdlib_context
讀取 Youtube 影片資訊
參考「pytube - YouTube Object」說明,使用 pytube 讀取 Youtube 網址後,就能取得關於該影片的各種資訊,下方的例子會取出標題、作者、作者頻道網址、影片縮圖網址、影片長度、觀看次數等資訊。
import ssl
ssl._create_default_https_context = ssl._create_stdlib_context
from pytube import YouTube
yt = YouTube('https://www.youtube.com/watch?v=R93ce4FZGbc') # baby shark 的音樂
print(yt.title) # 影片標題
print(yt.length) # 影片長度 ( 秒 )
print(yt.author) # 影片作者
print(yt.channel_url) # 影片作者頻道網址
print(yt.thumbnail_url) # 影片縮圖網址
print(yt.views) # 影片觀看數
下載 Youtube 影片為 mp4
參考「pytube - StreamQuery Object」說明,可以使用 get_highest_resolution() 方法,下載最高畫質的影片。
import ssl
ssl._create_default_https_context = ssl._create_stdlib_context
import os
os.chdir('/content/drive/MyDrive/Colab Notebooks') # 使用 Colab 要換路徑使用
from pytube import YouTube
yt = YouTube('https://www.youtube.com/watch?v=R93ce4FZGbc')
print('download...')
yt.streams.filter().get_highest_resolution().download(filename='baby_shart.mp4')
# 下載最高畫質影片,如果沒有設定 filename,則以原本影片的 title 作為檔名
print('ok!')
如果要指定下載影片的畫質,可以透過 get_by_resolution() 方法,填入像是 720p、480p、360p、240p 等標準影像解析度格式,就能下載對應的畫質 ( 注意,畫質會必須取決於該影片實際大小是否支援 )
import ssl
ssl._create_default_https_context = ssl._create_stdlib_context
import os
os.chdir('/content/drive/MyDrive/Colab Notebooks') # 使用 Colab 要換路徑使用
from pytube import YouTube
yt = YouTube('https://www.youtube.com/watch?v=R93ce4FZGbc')
print('download...')
yt.streams.filter().get_by_resolution('360p').download(filename='oxxostudio_360p.mp4')
# 下載 480p 的影片畫質
print('ok!')
如果想知道影片支援哪些畫質,可印出 streams.all() 來查看。
from pytube import YouTube
yt = YouTube('https://www.youtube.com/watch?v=R93ce4FZGbc')
print(yt.streams.all())
透過宣告 yt 時的參數 on_progress_callback,可以回傳目前下載影片的進度 ( 可顯示下載進度 )。
import ssl
ssl._create_default_https_context = ssl._create_stdlib_context
from pytube import YouTube
def onProgress(stream, chunk, remains):
total = stream.filesize # 取得完整尺寸
percent = (total-remains) / total * 100 # 減去剩餘尺寸 ( 剩餘尺寸會抓取存取的檔案大小 )
print(f'下載中… {percent:05.2f}', end='\r') # 顯示進度,\r 表示不換行,在同一行更新
print('download...')
yt = YouTube('https://www.youtube.com/watch?v=R93ce4FZGbc', on_progress_callback=onProgress)
yt.streams.filter().get_highest_resolution().download(filename='oxxostudio.mp4')
# on_progress_callback 參數等於 onProgress 函式
print()
print('ok!')
如果有出現「pytube.exceptions.AgeRestrictedError:XXXXXXXXX is age restricted, and can't be accessed without logging in.
」的錯誤情況,這可能是 pytube 的 bug 造成,參考「stackoverflow」的解決方法,在開頭加上下面這段程式碼就能解決。
from pytube.innertube import _default_clients
_default_clients["ANDROID_MUSIC"] = _default_clients["ANDROID_CREATOR"]
下載 Youtube 影片為 mp3
使用 get_audio_only() 方法,能單獨取出 Youtube 的音軌儲存為 mp3 檔案 ( 預設為 mp4,存檔時改檔名為 mp3 就會變成 mp3 )。
import ssl
ssl._create_default_https_context = ssl._create_stdlib_context
import os
os.chdir('/content/drive/MyDrive/Colab Notebooks') # 使用 Colab 要換路徑使用
from pytube import YouTube
yt = YouTube('https://www.youtube.com/watch?v=R93ce4FZGbc')
print('download...')
yt.streams.filter().get_audio_only().download(filename='oxxostudio.mp3')
# 儲存為 mp3
print('ok!')
下載 Youtube 影片字幕為 srt 或 txt
使用 yt.captions 方法,可以取得該 Youtube 影片全部的字幕 ( 如果是 auto 自動產生,字幕語系前方會出現 a. 標示 ),取得字幕後,透過 xml_captions 就能將指定語系的字幕轉換成 xml 檔案。
由於 pytube 內建的 generate_srt_captions() 方法會發生 KeyError: 'start' 錯誤,因此直接使用 BeautifulSoup 套件讀取 xml 的內容,再透過數學計算和字串格式化的方法,轉換成字幕檔案格式,最後輸出成為 srt 或 txt。
import ssl
ssl._create_default_https_context = ssl._create_stdlib_context
import os
os.chdir('/content/drive/MyDrive/Colab Notebooks') # 使用 Colab 要換路徑使用
from pytube import YouTube
from bs4 import BeautifulSoup
yt = YouTube('https://www.youtube.com/watch?v=R93ce4FZGbc')
print(yt.captions) # 取得所有語系
caption = yt.captions.get_by_language_code('en') # 取得英文語系
xml = caption.xml_captions # 將語系轉換成 xml
#print(xml)
def xml2srt(text):
soup = BeautifulSoup(text) # 使用 BeautifulSoup 轉換 xml
ps = soup.findAll('p') # 取出所有 p tag 內容
output = '' # 輸出的內容
num = 0 # 每段字幕編號
for i, p in enumerate(ps):
try:
a = p['a'] # 如果是自動字幕,濾掉有 a 屬性的 p tag
except:
try:
num = num + 1 # 每段字幕編號加 1
text = p.text # 取出每段文字
t = int(p['t']) # 開始時間
d = int(p['d']) # 持續時間
h, tm = divmod(t,(60*60*1000)) # 轉換取得小時、剩下的毫秒數
m, ts = divmod(tm,(60*1000)) # 轉換取得分鐘、剩下的毫秒數
s, ms = divmod(ts,1000) # 轉換取得秒數、毫秒
t2 = t+d # 根據持續時間,計算結束時間
if t2 > int(ps[i+1]['t']): t2 = int(ps[i+1]['t']) # 如果時間算出來比下一段長,採用下一段的時間
h2, tm = divmod(t2,(60*60*1000)) # 轉換取得小時、剩下的毫秒數
m2, ts = divmod(tm,(60*1000)) # 轉換取得分鐘、剩下的毫秒數
s2, ms2 = divmod(ts,1000) # 轉換取得秒數、毫秒
output = output + str(num) + '\n' # 產生輸出的檔案,\n 表示換行
output = output + f'{h:02d}:{m:02d}:{s:02d},{ms:03d} --> {h2:02d}:{m2:02d}:{s2:02d},{ms2:03d}' + '\n'
output = output + text + '\n'
output = output + '\n'
except:
pass
return output
#print(xml2srt(xml))
with open('oxxostudio.srt','w') as f1:
f1.write(xml2srt(xml)) # 儲存為 srt
print('ok!')
參考資料
意見回饋
如果有任何建議或問題,可傳送「意見表單」給我,謝謝~