Не могу скачать видео с ютуба

У меня возникли проблемы с автоматическим получением видео с YouTube. Вот код. Проблема в последней части. download = urllib.request.urlopen(download_url).read()

    # Youtube video download script
    # 10n1z3d[at]w[dot]cn

    import urllib.request
    import sys

    print("\n--------------------------")
    print (" Youtube Video Downloader")
    print ("--------------------------\n")

    try:
            video_url = sys.argv[1]
    except:
            video_url = input('[+] Enter video URL: ')

    print("[+] Connecting...")
    try:
            if(video_url.endswith('&feature=related')):
                    video_id = video_url.split('www.youtube.com/watch?v=')[1].split('&feature=related')[0]
            elif(video_url.endswith('&feature=dir')):
                    video_id = video_url.split('www.youtube.com/watch?v=')[1].split('&feature=dir')[0]
            elif(video_url.endswith('&feature=fvst')):
                    video_id = video_url.split('www.youtube.com/watch?v=')[1].split('&feature=fvst')[0]
            elif(video_url.endswith('&feature=channel_page')):
                    video_id = video_url.split('www.youtube.com/watch?v=')[1].split('&feature=channel_page')[0]
            else:
                    video_id = video_url.split('www.youtube.com/watch?v=')[1]
    except:
            print("[-] Invalid URL.")
            exit(1)       
    print("[+] Parsing token...")
    try:
            url = str(urllib.request.urlopen('http://www.youtube.com/get_video_info?&video_id=' + video_id).read())
            token_value = url.split('video_id='+video_id+'&token=')[1].split('&thumbnail_url')[0]

            download_url = "http://www.youtube.com/get_video?video_id=" + video_id + "&t=" + token_value + "&fmt=18"
    except:
            url = str(urllib.request.urlopen('www.youtube.com/watch?v=' + video_id))
            exit(1)

    v_url=str(urllib.request.urlopen('http://'+video_url).read())   
    video_title = v_url.split('"rv.2.title": "')[1].split('", "rv.4.rating"')[0]
    if '"' in video_title:
            video_title = video_title.replace('"','"')
    elif '&' in video_title:
            video_title = video_title.replace('&','&')

    print("[+] Downloading " + '"' + video_title + '"...')
    try:
            print(download_url)
            file = open(video_title + '.mp4', 'wb')
            download = urllib.request.urlopen(download_url).read()
            print(download)
            for line in download:
                    file.write(line)
                    file.close()
    except:
            print("[-] Error downloading. Quitting.")
            exit(1)

    print("\n[+] Done. The video is saved to the current working directory(cwd).\n")

Есть сообщение об ошибке: (спасибо Wooble)

Traceback (most recent call last):
  File "C:/Python31/MyLib/DrawingBoard/youtube_download-.py", line 52, in <module>
    download = urllib.request.urlopen(download_url).read()
  File "C:\Python31\lib\urllib\request.py", line 119, in urlopen
    return _opener.open(url, data, timeout)
  File "C:\Python31\lib\urllib\request.py", line 353, in open
    response = meth(req, response)
  File "C:\Python31\lib\urllib\request.py", line 465, in http_response
    'http', request, response, code, msg, hdrs)
  File "C:\Python31\lib\urllib\request.py", line 385, in error
    result = self._call_chain(*args)
  File "C:\Python31\lib\urllib\request.py", line 325, in _call_chain
    result = func(*args)
  File "C:\Python31\lib\urllib\request.py", line 560, in http_error_302
    return self.parent.open(new, timeout=req.timeout)
  File "C:\Python31\lib\urllib\request.py", line 353, in open
    response = meth(req, response)
  File "C:\Python31\lib\urllib\request.py", line 465, in http_response
    'http', request, response, code, msg, hdrs)
  File "C:\Python31\lib\urllib\request.py", line 391, in error
    return self._call_chain(*args)
  File "C:\Python31\lib\urllib\request.py", line 325, in _call_chain
    result = func(*args)
  File "C:\Python31\lib\urllib\request.py", line 473, in http_error_default
    raise HTTPError(req.full_url, code, msg, hdrs, fp)
urllib.error.HTTPError: HTTP Error 403: Forbidden   

person Kev    schedule 20.04.2010    source источник
comment
Вы действительно думаете, что можете просто взять поток Youtube и сохранить его как файл mp4? Особенно забавно выглядит попытка for line in download над бинарным потоком.   -  person Tim Pietzcker    schedule 21.04.2010
comment
Тим, во-первых, это не мой код, я просто модифицировал его для python3k. Во-вторых, если я введу URL-адрес в своем браузере, я смогу сохранить его как mp4. Ты кажешься умным, что ты предлагаешь мне делать тогда?   -  person Kev    schedule 21.04.2010
comment
Ошибка здесь кажется уместной. Это ошибка, которую выдает вам сервер. Это запрещено.   -  person Thomas Wouters    schedule 21.04.2010
comment
Это правда, но если я введу URL-адрес вручную в своем браузере, он сработает, и я смогу его загрузить.   -  person Kev    schedule 21.04.2010
comment
Можете ли вы опубликовать полный вывод этой программы. Меня интересует, что выводят операторы печати.   -  person ktdrv    schedule 21.04.2010
comment
Я не уверен, что вы имеете в виду под всем выводом, весь исходный код и сообщения об ошибках, которые я получил, есть, не могли бы вы уточнить?   -  person Kev    schedule 21.04.2010
comment
Вот руководство о том, как это сделать: willdrevo .com/   -  person lollercoaster    schedule 28.02.2015


Ответы (5)


Код исходного вопроса основан на нескольких предположениях о содержании страниц и URL-адресов YouTube (выраженных в таких конструкциях, как "url.split('something=')[1]"), которые не всегда могут быть верными. Я проверил это, и это может зависеть даже от того, какие похожие видео отображаются на странице. Возможно, вы споткнулись на любой из этих особенностей.

Вот более чистая версия, которая использует urllib для анализа URL-адресов и строк запроса и успешно загружает видео. Для ясности я удалил некоторые команды try/except, которые ничего не делали, кроме выхода. Кстати, он работает с заголовками видео в формате Unicode, удаляя символы, отличные от ascii, из имени файла, в котором сохраняется видео. Он также принимает любое количество URL-адресов YouTube и загружает их все. Наконец, он маскирует свой пользовательский агент как Chrome для Mac (это то, что я сейчас использую).

#!/usr/bin/env python3

import sys
import urllib.request
from urllib.request import urlopen, FancyURLopener
from urllib.parse import urlparse, parse_qs, unquote

class UndercoverURLopener(FancyURLopener):
    version = "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_8; en-US) AppleWebKit/533.2 (KHTML, like Gecko) Chrome/5.0.342.9 Safari/533.2"
urllib.request._urlopener = UndercoverURLopener()

def youtube_download(video_url):
    video_id = parse_qs(urlparse(video_url).query)['v'][0]

    url_data = urlopen('http://www.youtube.com/get_video_info?&video_id=' + video_id).read()
    url_info = parse_qs(unquote(url_data.decode('utf-8')))
    token_value = url_info['token'][0]

    download_url = "http://www.youtube.com/get_video?video_id={0}&t={1}&fmt=18".format(
        video_id, token_value)

    video_title = url_info['title'][0] if 'title' in url_info else ''
    # Unicode filenames are more trouble than they're worth
    filename = video_title.encode('ascii', 'ignore').decode('ascii').replace("/", "-") + '.mp4'

    print("\t Downloading '{}' to '{}'...".format(video_title, filename))

    try:
        download = urlopen(download_url).read()
        f = open(filename, 'wb')
        f.write(download)
        f.close()
    except Exception as e:
        print("\t Downlad failed! {}".format(str(e)))
        print("\t Skipping...")
    else:
        print("\t Done.")

def main():
    print("\n--------------------------")
    print (" Youtube Video Downloader")
    print ("--------------------------\n")

    try:
        video_urls = sys.argv[1:]
    except:
        video_urls = input('Enter (space-separated) video URLs: ')

    for u in video_urls:
        youtube_download(u)
    print("\n Done.")

if __name__ == '__main__':
    main()
person rbp    schedule 20.04.2010
comment
Только что сделал небольшое редактирование, чтобы исправить ложную одиночную галочку, которая появлялась в заголовке видео. - person rbp; 21.04.2010
comment
спасибо за ваши усилия, теперь код выглядит намного чище, я должен был удалить операторы try, кроме операторов. однако это все еще приводит к ошибке, когда я пытаюсь загрузить видео. - person Kev; 21.04.2010
comment
В строке url_info, если я не ошибаюсь, есть дополнительный ')' - person Kev; 21.04.2010
comment
возможно, YouTube знает, что это программа, если я изменю заголовки запроса, я смогу имитировать пользователя-человека. - person Kev; 21.04.2010
comment
Правда, есть дополнительный ')', оставленный, когда я редактировал ответ. Я удаляю это. Вы все еще получаете ошибку «Запрещено»? Возможно, вы пытаетесь слишком часто, и YouTube блокирует вас. Я скачал несколько разных видео с этим кодом. Это может быть и конкретное видео. Какой из них вы пытаетесь скачать? Например, я скачал youtube.com/watch?v=OEDP6xfAiVw несколько раз. с приведенным выше кодом, без дальнейших проблем ([+] Загрузка 'Велоспорт в Амстердаме'... -> Велоспорт в Амстердаме.mp4). Попробуйте скачать этот. - person rbp; 21.04.2010
comment
Кстати, я вообще не менял заголовки, и это сработало. Если вы пытались слишком часто, возможно, они заблокировали ваш IP, по крайней мере, на какое-то время. - person rbp; 21.04.2010
comment
Еще раз отредактировано, чтобы более элегантно работать с заголовками видео в юникоде. Я также изменил код, чтобы использовать форматирование строк в стиле python3 вместо объединения строк с помощью + - person rbp; 22.04.2010
comment
Я очень ценю усилия, которые вы приложили к сценарию, я все еще получаю ту же ошибку, я заметил, что ваш метод извлечения видео примерно такой же, как метод в сценарии, который я разместил. - person Kev; 22.04.2010
comment
Мне удалось избавиться от 403, я думаю, добавив параметр хоста как часть заголовка. - person Kev; 22.04.2010
comment
Я еще не проверил как следует сценарий Джейка, но он выглядит неплохо (с бонусными баллами за скачивание с Vimeo). Тем не менее, мне нравится этот загрузчик, поэтому я реструктурировал его, чтобы он загружал произвольное количество видео. Он также маскируется под веб-браузер, что может помочь вам с запрещенной ошибкой (но я никогда не получаю ее, поэтому я не могу ее правильно протестировать). - person rbp; 23.04.2010

Я собираюсь без зазрения совести подключить мой скрипт, который автоматизирует проверку допустимых форматов, автоматически выбирая наилучшие качественный формат для видео и работает как с вариантами flash, так и с html5 на страницах YouTube (а также на Vimeo).

Если вы написали этот скрипт, посмотрите мой исходный код для вдохновения и не стесняйтесь украсть какой-нибудь код. Я призываю вас, пожалуйста, напишите что-нибудь лучше. Открытый код процветает благодаря конкуренции!

Однако, если вы скопировали этот сценарий и просто пытаетесь заставить его работать, могу ли я предложить вам попробовать мой сценарий и посмотреть, будет ли он лучше для вас. Вы можете получить к нему доступ как из командной строки в виде скрипта, так и даже в виде модуля в другом файле Python.

(изменить: создал вики, не думая о репутации.)

person Community    schedule 22.04.2010
comment
Просто хотел посмотреть, как работает сценарий, который я разместил. Спасибо, что выложили свой, пойду посмотрю. - person Kev; 22.04.2010
comment
Эй, можно ли вытащить пару ключ: значение из заголовка ответа http, который вы получаете от YouTube? получить_заголовки? - person Kev; 22.04.2010
comment
Я ввел заголовки, на этот раз ошибок нет, но размер файла слишком мал для видео, нужно ли буферизовать загрузку? Как я могу это сделать? также у вас есть процедура download_callback? что это делает? - person Kev; 22.04.2010
comment
Также добавить, используя urllib, если страница, которую я запрашиваю, перенаправлена, как мне заставить urllib вернуть перенаправленный адрес? - person Kev; 22.04.2010
comment
Как видно из docs.python.org/library/urllib2.html#urllib2 .urlopen вы можете использовать .info() для получения информации заголовка из возвращаемого объекта. Функция download_callback используется только для Vimeo, чтобы определить, является ли файл MP4 или MOV. Я не уверен, как работают перенаправления, но в urllib2 есть класс HTTPRedirectHandler. - person Jake Wharton; 22.04.2010

Вы также можете проверить youtube-dl, который написан на Python, и проверить, как он написан:

https://github.com/rg3/youtube-dl

person kenorb    schedule 14.07.2013
comment
Достойный учебник по использованию youtube-dl здесь: willdrevo.com / - person lollercoaster; 18.12.2014
comment
2015 отмеченный ответ не сработал для меня, это сделало славу - person Lazik; 16.10.2015

Похоже, ребята из YouTube изменили алгоритмы доступа к видеофайлам. Вместо «токена» они теперь используют переменную «подпись», а «подпись», похоже, зависит либо от данных, хранящихся в файлах cookie, либо от IP-адреса клиента (в случае браузера с отключенными файлами cookie, такого как urllib в python-2). Вот хак, который я придумал (URL-адреса заблокированы по IP):

#!/usr/bin/python

import re
from urlparse import *
from urllib import *

def yt_url(video_url):
    video_id = parse_qs(urlparse(video_url).query)['v'][0]

    get_vars = parse_qs(unquote(urlopen("http://www.youtube.com/get_video_info?video_id="+video_id).read()))

    url = get_vars["id"][0].split(",")[1].split("|")[1]

    elements = dict()
    elements["itag"] = get_vars["itag"][0]
    elements["sver"] = get_vars["sver"][0]
    elements["expire"] = get_vars["expire"][0]
    elements["signature"] = get_vars["signature"][0]
    elements["factor"] = get_vars["factor"][0]
    elements["id"] = get_vars["id"][0].split(",")[0]
    elements["key"] = get_vars["key"][0]
    elements["burst"] = get_vars["burst"][0]
    elements["sparams"] = get_vars["sparams"][0]
    elements["algorithm"] = get_vars["algorithm"][0]
    elements["ipbits"] = "8"

    for get_var in elements:
      url += "&" + get_var + "=" + elements[get_var]

    return (get_vars["title"][0], url)

if __name__ == '__main__':
    (title, url) = yt_url("http://www.youtube.com/watch?v=4tAr7tuakt0")
    print "Title: %s" % (title,)
    print "Video: %s" % (url,)
person Darko Ilic    schedule 25.05.2010

person    schedule
comment
Это мое первое практическое кодирование Python в загрузчик YouTube. Это последняя загрузка видео с YouTube в соответствии с алгоритмом YouTube. - person Teron; 23.10.2012
comment
Вероятно, вам следует включить эту информацию в свой ответ, чтобы это был не просто код (вы можете отредактировать свой ответ, нажав кнопку редактирования под ним). - person Jack; 23.10.2012