芋の独り言

ジャンル問わず,ちょっとしたことを備忘録的なものとして,つぶやいていこうと思います

YouTubeダウンローダ― with Python

kusoimox.hatenablog.jp
以前うpした記事で,pytubeYouTubeの動画がダウンロードできる~とい言ったんですが,最近久しぶりに使うと, itagは取れるんだけど,動画のダウンロードでエラーが出て,使えなくなちゃった...
そこで,調べると,

っとあったんですが,原因が少し違うような...よう分りまへんわ~
っということで,それならスクリプト自作してしまえってことになり,以下のようになりました. スクリプト構成の土台はpytubeですけどね.

# -*- coding: utf-8 -*-
# 動画
movie = [5,6,17,18,22,34,35,37,38,43,44,45,46,59,78,82,83,84,85,91,92,93,94,
    95,96,100,101,102,132,151]
# 動画像のみ
video = [13,36,133,134,135,136,137,138,160,167,168,169,170,212,218,219,242,
    243,244,245,246,247,248,264,266,271,272,278,298,299,302,303,308,313,
    315,330,331,332,333,334,335,336,337]
# 音声のみ
audio =[139,140,141,171,172,249,250,251]


from urllib.parse import unquote
from time import sleep
import re,sys,requests,ast,wx,os

class youtube:
    
    def save(self):
        app=wx.App() # アプリケーションのオプジェクトを生成
        wx.MessageBox('保存先フォルダを選択してください','フォルダ選択',wx.STAY_ON_TOP)
        dialog = wx.DirDialog(None, message='ファイルを選択してください',style=wx.DD_CHANGE_DIR | wx.OK | wx.STAY_ON_TOP)
        # ファイルが選択されたとき
        if dialog.ShowModal() == wx.ID_OK:
        # 選択したファイルパスを取得する
            self.path = dialog.GetPath()
            dialog.Destroy()
    
    def download(self,itag_no):
        itag_no = int(itag_no)
        for i in self.itag:
            if i['itag'] == itag_no:
                dl_url = i['url']
                break
            
        title = re.sub(r'[\\/:*?"<>|]+','',self.videoDetails['title'].replace(' ',''))
        if (itag_no in movie) or (itag_no in video):
            kakuchoshi = '.mp4'
        elif itag_no in audio:
            kakuchoshi = '.wmv'
        title = title + kakuchoshi

        path = os.path.join(self.path,title)

        sys.stderr.write('downloading...\n')
        data = requests.get(dl_url).content
        with open(title,mode='wb') as f:
            f.write(data)
            
        sys.stderr.write('download finish!\n')

    def video_info_url(self,url):
        video_id  = re.search(r'(?:v=|\/)([0-9A-Za-z_-]{11}).*', url).groups(1)[0]
        if video_id == None:
            return False
        watch_url = 'https://youtube.com/watch?v=' + video_id
        watch_html = requests.get(watch_url).content.decode()
        eurl = 'https://youtube.googleapis.com/v/{}'.format(video_id)
        embed_html = 'https://www.youtube.com/embed/{}'.format(video_id)

        params = {
            'video_id':video_id,
            'el':'detailpage',
            'ps':'default',
            'hl':'en_US'
        }
        
        rurl = requests.get('https://youtube.com/get_video_info',params=params).url
        res = unquote(requests.get(rurl+'?eurl={}'.format(eurl)).text)

        self.itag=[]
        info = re.search(r'player_response=({.+})&',res)
        if info != None:
            info = info.groups(1)[0]
            info = info.strip()
            info = info.replace('"',"'")
            info = info.replace('true','True')
            info = info.replace('false','False')
            info = info.replace('null','None')
            try:
                video_info = ast.literal_eval(info)
            except SyntaxError:
                return False

            del info
        else:
            return False
            
        streamingData = video_info['streamingData']
        self.itag += streamingData['formats']
        self.itag += streamingData['adaptiveFormats']
        self.playbackTracking = video_info['playbackTracking']
        self.videoDetails = video_info['videoDetails']

        return True
    
    def __init__(self,url):
        self.save()

        sys.stderr.write('info getting...\n')
        while True:
            try:
                res = self.video_info_url(url)
            except requests.exceptions.SSLError:
                continue
            except requests.exceptions.ConnectionError:
                continue
            if res:
                break
            sleep(60)

        for i in self.itag:
            if i['itag'] in movie:
                sys.stderr.write('動画    ')
            elif i['itag'] in video:
                sys.stderr.write('動画像のみ ')
            elif i['itag'] in audio:
                sys.stderr.write('音声のみ  ')
            else:
                sys.stderr.write('None ')
            sys.stderr.write('itag {0}:[type:{1} bitrate:{2} quality:{3}]\n'.format(
                i['itag'],i['mimeType'].split('=')[-1],i['bitrate'],i['quality']
                ))

if __name__ == '__main__':
    url = input('url:')
    yt = youtube(url)
    yt.download(input('choice itag number:'))

https://www.youtube.com/watch?v=動画ID&feature=youtu.be”みたいなURLが対象です.基本はこの形のURLで. え~と,”https://youtu.be/動画ID”でもイケましたね.共有からURLをコピーしたときはこの形ですからね. 通常はitagを22,なければ18を選択すれば,動画がダウンロードできます.

参考

pytubePython参考書