代码之家  ›  专栏  ›  技术社区  ›  Nick D

如何在Python中从Youtube URL流式传输音频(无需下载)?

  •  11
  • Nick D  · 技术社区  · 7 年前

    我一直在尝试创建一种从python代码流式传输youtube url的方法(最好是仅音频,尽管这并不重要)。我尝试了很多方法,但似乎都没有真正奏效。到目前为止,我能够使用youtube数据api搜索视频或播放列表,抓取第一个视频或播放列表并将其传递到pafy中,以获得不同的流式URL。有人知道一种不用先下载视频就可以通过python播放youtube音频/视频的方法吗?我认为使用命令行工具(如mplayer或vlc)可以使用子进程弹出命令行的命令并传入url,但我被卡住了。需要任何帮助。请以下是我的代码:

    import argparse
    import pafy
    from googleapiclient.discovery import build
    from googleapiclient.errors import HttpError
    
    DEVELOPER_KEY = 'DEVELOPER KEY'
    YOUTUBE_API_SERVICE_NAME = 'youtube'
    YOUTUBE_API_VERSION = 'v3'
    
    def pafy_video(video_id):
        url = 'https://www.youtube.com/watch?v={0}'.format(video_id)
        vid = pafy.new(url)
    
    def pafy_playlist(playlist_id)
        url = "https://www.youtube.com/playlist?list={0}".format(playlist_id)
        playlist = pafy.get_playlist(url)
    
    
    def youtube_search(options):
      youtube = build(YOUTUBE_API_SERVICE_NAME, YOUTUBE_API_VERSION, developerKey=DEVELOPER_KEY)
    
      search_response = youtube.search().list(
        q='Hello world',
        part='id,snippet',
        maxResults=options.max_results
      ).execute()
    
      videos = []
      playlists = []
      channels = []
      for search_result in search_response.get('items', []):
        if search_result['id']['kind'] == 'youtube#video':
          videos.append('%s' % (search_result['id']['videoId']))
        elif search_result['id']['kind'] == 'youtube#channel':
          channels.append('%s' % (search_result['id']['channelId']))
        elif search_result['id']['kind'] == 'youtube#playlist':
          playlists.append('%s' % (search_result['id']['playlistId']))
    
    
      if videos:
        print('Videos:{0}'.format(videos))
        pafy_video(videos[0])
      elif playlists:
        print('Playlists:{0}'.format(playlists))
        pafy_video(playlists[0])
    
      #https://www.youtube.com/watch?v=rOU4YiuaxAM
      #url = 'https://www.youtube.com/watch?v={0}'.format(videos[0])
      #print(url)
    
    if __name__ == '__main__':
      parser = argparse.ArgumentParser()
      parser.add_argument('--q', help='Search term', default='Google')
      parser.add_argument('--max-results', help='Max results', default=3)
      args = parser.parse_args()
      youtube_search(args)
    

    太长,读不下去了我想直接从python代码流式传输youtube视频(使用url或id),而无需先下载视频

    非常感谢。

    2 回复  |  直到 5 年前
        1
  •  12
  •   Martí Climent    3 年前

    pafy 根据its documentation 不要直接列出正在播放的媒体(至少我没有找到)。

    然而,我们可以使用它来获得正确的url,然后使用播放器,例如 vlc 无需下载即可直接播放。

    您可以下载 vlc from here

    首先,我们从 youtube 使用 帕菲

    import pafy
    import vlc
    
    url = "https://www.youtube.com/watch?v=bMt47wvK6u0"
    video = pafy.new(url)
    best = video.getbest()
    playurl = best.url
    

    在这里 playurl 是播放的最佳URL。 然后我们用VLC来播放它。

    Instance = vlc.Instance()
    player = Instance.media_player_new()
    Media = Instance.media_new(playurl)
    Media.get_mrl()
    player.set_media(Media)
    player.play()
    

    这将打开一个没有控件的窗口(播放/暂停/停止等)。 您可以在 repr 窗口或python提示(取决于您使用它的方式)
    您需要使用vlc命令相应地构建一个,例如

    >>> player.pause() #-- to pause video
    >>> player.play()  #-- resume paused video. On older versions, 
                       #     this function was called resume
    >>> player.stop()  #-- to stop/end video
    
        2
  •  7
  •   Rook Crossfield    4 年前

    实现这一点的最佳方法是使用 mpv 具有 youtube-dl (一种轻量级媒体播放器,配有命令行控制台,允许您通过将url复制和粘贴到mpv控制台来流式传输任何类型的视频/音频编解码器(适用于cmd和终端)。 用法 :路径\到\mpvhttps://your/video/audioURL.com/

    首先导入这些模块-通过安装 pip install bs4 requests

    import re, requests, subprocess, urllib.parse, urllib.request
    from bs4 import BeautifulSoup
    

    然后创建一个变量来存储您选择的音乐标题

    music_name = "Linkin Park Numb"
    query_string = urllib.parse.urlencode({"search_query": music_name})
    

    这里的目标是使用此搜索查询提取第一个视频结果的输出标题和链接。然后我们可以对youtube url进行结束编码 "https://www.youtube.com/results?search_query=" 标识符使用 urllib (例如。, "https://www.youtube.com/results?search_query=linkin+park+numb" )

    formatUrl = urllib.request.urlopen("https://www.youtube.com/results?" + query_string)
    

    这个就在这里 re.findall(r"watch\?v=(\S{11})" 查看我们查询的所有视频结果的11个字符标识符

    search_results = re.findall(r"watch\?v=(\S{11})", formatUrl.read().decode())
    

    解码内容后,我们可以通过将主youtube url与11个字符的标识符连接起来来提取完整的url

    clip = requests.get("https://www.youtube.com/watch?v=" + "{}".format(search_results[0]))
    clip2 = "https://www.youtube.com/watch?v=" + "{}".format(search_results[0])
    
    print(clip2)
    
    • 输出==> https://www.youtube.com/watch?v=kXYiU_JCYtU

    为了进一步检查内容,我们可以使用beautifulsoup来刮取视频的extact标题

    inspect = BeautifulSoup(clip.content, "html.parser")
    yt_title = inspect.find_all("meta", property="og:title")
    
    for concatMusic1 in yt_title:
        pass
    
    print(concatMusic1['content'])
    
    • 输出==> Numb (Official Video) - Linkin Park

    最后,为了播放音乐,我们将其输入到命令行

    subprocess.Popen(
    "start /b " + "path\\to\\mpv.exe" + clip2 + " --no-video --loop=inf --input-ipc-server=\\\\.\\pipe\\mpv-pipe > output.txt",
    shell=True)
    

    完整脚本

    ===================================================================

    import re, requests, subprocess, urllib.parse, urllib.request
    from bs4 import BeautifulSoup
    
    music_name = "Linkin Park Numb"
    query_string = urllib.parse.urlencode({"search_query": music_name})
    formatUrl = urllib.request.urlopen("https://www.youtube.com/results?" + query_string)
    
    search_results = re.findall(r"watch\?v=(\S{11})", formatUrl.read().decode())
    clip = requests.get("https://www.youtube.com/watch?v=" + "{}".format(search_results[0]))
    clip2 = "https://www.youtube.com/watch?v=" + "{}".format(search_results[0])
    
    inspect = BeautifulSoup(clip.content, "html.parser")
    yt_title = inspect.find_all("meta", property="og:title")
    
    for concatMusic1 in yt_title:
        pass
    
    print(concatMusic1['content'])
    
    subprocess.Popen(
    "start /b " + "path\\to\\mpv.exe " + clip2 + " --no-video --loop=inf --input-ipc-server=\\\\.\\pipe\\mpv-pipe > output.txt",
    shell=True)
    
    
    # Alternatively, you can do this for simplicity sake:
    # subprocess.Popen("start /b " + "path\\to\\mpv.exe " + clip2 + "--no-video", shell=True)