iT邦幫忙

2

(2020年1月最新)如何用python下載youtube影片?

撰文說明:
現代在youtube看影片已成為多數人的休閒娛樂,
當中或許會看到一些值得珍藏的影片,
然而網路上下載youtube影片的方法很多不太好用,
今天就來介紹如何使用python來幫我們方便的下載影片。

開發環境:
小馬使用的是anaconda的spyder,python版本為3.7,
安裝anaconda的方法可參考之前寫過的一篇基礎教學-
【Python 超入門】(1) 心原一馬從零開始帶你學程式

關鍵技術- 下載pytube模組

我們將使用一個叫作pytube的模組來幫助我們下載影片,
由於pytube並非內建的模組,我們需要另外安裝它,
安裝方式也很簡單,
安裝好anaconda後,你可以在開始->程式集的地方找到一個叫anaconda的資料夾,大概如下:
https://ithelp.ithome.com.tw/upload/images/20200116/20117114ZHXcyPaoJX.png

選擇anaconda prompt點擊它,
會看到這樣的畫面:
https://ithelp.ithome.com.tw/upload/images/20200116/20117114UuWZuAYkGf.png

輸入指令pip install pytube==9.5.3,按下enter,
(最後等號後面表示版本號碼,若省略==9.5.3則會安裝最新版本)
看到Successfully installed pytube-9.5.3就表示安裝完成了,如下:

https://ithelp.ithome.com.tw/upload/images/20200116/20117114Omwzu7A7XI.png

至今天為止pytube的最新版本即為9.5.3。

程式簡單- 三行程式碼即可下載影片

進入程式碼教學,
譬如你想要下載的youtube影片網址為https://www.youtube.com/watch?v=DG8sXuBzKuM
(這首歌為「阿拉丁 Whole new world 的翻唱」)
只需要撰寫下面三行程式碼:

from pytube import YouTube
yt = YouTube('https://www.youtube.com/watch?v=DG8sXuBzKuM')
yt.streams.first().download()

第1行: 匯入pytube這個模組
第2行: 建立一個YouTube物件,括號內填入欲下載影片的網址
第3行: youtube的每部影片可能有多種不同格式供使用者下載,通常選第一種下載即可。
download()方法默認會將影片下載至跟你的程式同一個資料夾中。

注意: 若你忘記依上述步驟於anaconda prompt安裝pytube而直接執行程式,
你會得到ModuleNotFoundError: No module named 'pytube'的錯誤。

大功告成?

然而當你在anaconda的spyder試圖編譯這支程式時,
仍然會得到一個錯誤訊息KeyError: 'url_encoded_fmt_stream_map',如下圖所示:
https://ithelp.ithome.com.tw/upload/images/20200116/20117114Ad6uHMJSZn.png
咦?難道在網路上的教學有誤嗎?
其實這支程式在幾個月前應該還是可以運作的,
只是可能YouTube網站本身對於這種使用爬蟲技術來下載影片的方法會常常換方式阻擋,
因此需要注意自己的pytube模組是否為最近版本,
但目前pytube-9.5.3已是最新版本了。

解決方案- 不會就先google吧

我們再嘗試將錯誤訊息KeyError: 'url_encoded_fmt_stream_map'拿去google,
順利找到解法how to deal with the issues:[url_encoded_fmt_stream_map]
根據網上的說明,
首先先點選程式錯誤訊息的in apply_descrambler,如下圖所示,
可以進入pytube底下的mixins.py這個檔案。

https://ithelp.ithome.com.tw/upload/images/20200116/20117114lrw7m8mNPJ.png

順利的話,會看到mixins.pyapply_descrambler這個函數:
https://ithelp.ithome.com.tw/upload/images/20200116/20117114w4BvFY8JX7.png

再來是重點了,請把apply_descrambler函數的內容,更換為底下的程式碼(注意程式碼放在函數中要縮排,即空四格或需要一個tab的距離)並存檔:

if key == 'url_encoded_fmt_stream_map' and not stream_data.get('url_encoded_fmt_stream_map'):
    formats = json.loads(stream_data['player_response'])['streamingData']['formats']
    formats.extend(json.loads(stream_data['player_response'])['streamingData']['adaptiveFormats'])
    stream_data[key] = [{u'url': format_item[u'url'],
                         u'type': format_item[u'mimeType'],
                         u'quality': format_item[u'quality'],
                         u'itag': format_item[u'itag']} for format_item in formats]
else:
    stream_data[key] = [
        {k: unquote(v) for k, v in parse_qsl(i)}
        for i in stream_data[key].split(',')
    ]
logger.debug(
    'applying descrambler\n%s',
    pprint.pformat(stream_data[key], indent=2),
)

此時再回頭編譯原來的那三行程式碼就真的大功告成了:

from pytube import YouTube
yt = YouTube('https://www.youtube.com/watch?v=DG8sXuBzKuM')
yt.streams.first().download()

此時可以看到下載完成的影片跟自己的程式(我命名為pytubePratice.py)置於同一個資料夾中了:
https://ithelp.ithome.com.tw/upload/images/20200116/2011711402jOq5H1w5.png

今後,若你想下載自己喜歡的youtube影片,只需要將第2行的網址換為自己的網址即可。

列印文字了解下載進度

為了讓我們了解影片下載的狀況,
我們可以於程式yt.streams.first().download()前後加入一些文字,如下:

from pytube import YouTube
yt = YouTube('https://www.youtube.com/watch?v=DG8sXuBzKuM')
print("下載程式中請稍後")
yt.streams.first().download()
print("下載影片完成")

一次下載多個影片的方法

那如果今天你一次想下載十個影片怎麼辦呢?
如果照上述程式的寫法,
一次下載一個影片,
每次更改第二行的網址寫挺麻煩的。
能否一次將十個網址輸入至程式中一次下載呢?

小馬自己的做法如下:
假設我想一次下載三個youtube影片,網址分別為
https://www.youtube.com/watch?v=aL91YOChFAo
https://www.youtube.com/watch?v=qsR4nuI28ck
https://www.youtube.com/watch?v=ziz8wnIf1jk
(三首動漫相關的歌曲)
小馬將網址複製貼上存在「video.txt」文字檔中(每個網址一行),

https://ithelp.ithome.com.tw/upload/images/20200117/20117114rw2gWRL2HO.png

並將這個檔案放在跟自己的python程式(我命名為pytubePratice.py)同一個資料夾中,
將python程式更改如下:

from pytube import YouTube
with open('video.txt') as file:
    for line in file:
        yt = YouTube(line.rstrip())
        print(f"正在下載影片: {yt.title}")
        yt.streams.first().download()
        print(f"影片{yt.title}下載完成")

用python程式讀取文字檔「video.txt」的內容,
即可一次下載多個影片囉。
(程式內print裡的yt.title可以顯示影片的名稱)

成果如圖示:
https://ithelp.ithome.com.tw/upload/images/20200117/201171146qj1zYF5JM.png
(pytubePratice.pyvideo.txt是自己先寫好的檔案,
下載影片完成後,可看到同一資料夾多了三個mp4檔案)

有些受版權保護的影片可能無法下載

雖然用python下載影片非常方便,
但小馬嘗試過仍然有些影片是會下載失敗的,
譬如https://www.youtube.com/watch?v=PdK2dqifYEs 這首歌
(此首為「星羅 Beautiful Wish」)
目前觀察到的規律是,
下載失敗的影片在youtube資訊中,
會標明「授權 YouTube 的內容擁有者:」,如圖示:
https://ithelp.ithome.com.tw/upload/images/20200116/20117114BHncAhSj2D.png

以上教學到此,
提醒大家於網路上下載的影片僅供個人觀賞用,
嚴禁做商業用途,避免觸法。

參考資料

  1. 【使用 pytube 下載 YouTube 的影片】
  2. how to deal with the issues:[url_encoded_fmt_stream_map]

2 則留言

1
wilson1966
iT邦研究生 5 級 ‧ 2020-01-17 13:51:48

不錯,標記一下
/images/emoticon/emoticon12.gif

謝謝~

0
q816697q
iT邦新手 5 級 ‧ 2020-01-20 10:18:34

我要下載多個影片怎麼失敗?
錯誤碼是[Errno 2] No such file or directory: 'video.txt'

邦友您好,錯誤碼No such file or directory: 'video.txt'表示程式找不到video.txt這個檔案,您可以-

  • 檢查你貼網址的文字檔命名是否叫做video.txt(副檔名.txt也要對才行。註: 若你電腦是設定「隱藏檔案的副檔名」,而你將文件命名為video.txt的話,那麼實際檔案的名稱可能會成video.txt.txt,需特別留意。)
  • 檢查video.txt是否跟你的python程式放在同一個資料夾中

希望有幫到你。

我要留言

立即登入留言