php 中的 Youtube 视频下载器失败 - 禁止

Posted

技术标签:

【中文标题】php 中的 Youtube 视频下载器失败 - 禁止【英文标题】:Youtube video downloader in php failed - forbidden 【发布时间】:2017-12-18 07:29:39 【问题描述】:

我来自孟加拉国。我有一个 youtube 下载器 php 脚本,但它无法下载一些视频。当我点击下载按钮时,它的下载视频播放并显示文本失败 - 禁止。

我无法下载与以下视频相同的视频。大部分视频未下载。

下载网址是:http://mcv12.masudtools.xyz/

比如这个视频:

https://www.youtube.com/watch?v=DL5-XssXkxo

我也有错误日志:

[2017 年 7 月 13 日 12:51:44 UTC] PHP 通知:未定义索引:/home/masudtoo/public_html/mcv12/VideoYoutubeProvider.php 中的 Adaptive_fmts 位于第 126 行 [13-Jul-2017 12:51:45 UTC] PHP 注意:未定义索引:在第 85 行输入 /home/masudtoo/public_html/mcv12/VideoYoutubeProvider.php [2017 年 7 月 13 日 12:51:45 UTC] PHP 通知:未定义的偏移量:第 88 行 /home/masudtoo/public_html/mcv12/VideoYoutubeProvider.php 中的 1

126 行是:

$adaptive_fmts = $this->fullInfo['adaptive_fmts'];

85 行是:

$type = explode(';', $item['type']);

88 行是:

$ext = $baseType[1];

完整的 VideoYoutubeProvider.php 代码:

class VideoYoutubeProvider extends VideoAbstractProvider


public $fullInfo = null;

/**
 * Get provider name
 * @return string
 */
public function getProviderName()

    return "Youtube video";


/**
 * Checks video url for belonging to this provider
 *
 * @param string $url video url for check
 * @return boolean returning true if service available this video url
 */
static public function checkUrl($url)

    return !!preg_match("/^.*((youtu.be\/)|(v\/)|(\/u\/\w\/)|(embed\/)|(watch\?))\??v?=?([^#\&\?]*).*/i", $url);


/**
 * Return base video information
 *
 * @return BaseVideoInfo
 * @throws VideoDownloaderBaseInfoException
 */
public function getBaseInfo()

    $fullInfo = $this->getFullInfo();
    $baseInfo = new BaseVideoInfo();
    $baseInfo->name = $fullInfo['title'];
    $videoId = $fullInfo['video_id'];
    $preview = new VideoPreviewUrl();
    $preview->width = 1280;
    $preview->height = 720;
    $preview->name = 'maxresdefault';
    $preview->url = "https://img.youtube.com/vi/$videoId/hqdefault.jpg";
    $baseInfo->previewUrls = [$preview];
    $baseInfo->mainPreviewUrl = $preview;
    $html = $fullInfo['html'];
    if (preg_match('/<p id="eow-description"[^>]+>(.+)<\/p>/', $html, $matches)) 
        $baseInfo->description = strip_tags(str_replace('<br />', "\n", $matches[1]));
    
    return $baseInfo;


/**
 * Return array of download information for video
 *
 * @return VideoDownloadInfo[]
 * @throws VideoDownloaderDownloadException
 */
public function getDownloadsInfo()

    $fullInfo = $this->getFullInfo();
    $fmts = $fullInfo['url_encoded_fmt_stream_map'];
    $downloadsInfo = [];
    $title = $fullInfo['title'];
    foreach ($fmts AS $item) 
        $url = $item['url'] . '&title=' . urlencode($title);
        $headers = RequestHelper::getResponseHeaders($url);
        $downloadInfo = new VideoDownloadInfo();
        $downloadInfo->fileSize = (int)$headers['Content-Length'];
        $downloadInfo->url = $url;
        $downloadInfo->fileType = $headers['Content-Type'];
        $ext = explode('/', $downloadInfo->fileType);
        $ext = $ext[1];
        $downloadInfo->name = $title . '.' . $ext;
        $downloadsInfo[] = $downloadInfo;
    
    $fmts = $fullInfo['adaptive_fmts'];
    foreach ($fmts AS $item) 
        $type = explode(';', $item['type']);
        $type = $type[0];
        $baseType = explode('/', $type);
        $ext = $baseType[1];
        $baseType = $baseType[0];
        if ($baseType === 'audio') 
            $downloadInfo = new VideoDownloadInfo();
            $downloadInfo->fileSize = (int)$item['clen'];
            $downloadInfo->name = $title . '.' . $ext;
            $url = $item['url'] . '&title=' . urlencode($title);
            $downloadInfo->url = $url;
            $downloadInfo->fileType = $type;
            $downloadsInfo[] = $downloadInfo;
            break;
        
    
    return $downloadsInfo;



private function getFullInfo()

    if (is_null($this->fullInfo))  
        preg_match("/^.*((youtu.be\/)|(v\/)|(\/u\/\w\/)|(embed\/)|(watch\?))\??v?=?([^#\&\?]*).*/i", $this->url, $matches);
        $videoId = $matches[7];
        $fullInfoSource = file_get_contents("http://www.youtube.com/get_video_info?&video_id=$videoId&asv=3&el=detailpage&hl=en_US");
        $fullInfoSource = explode('&', $fullInfoSource);
        $this->fullInfo = [];
        foreach ($fullInfoSource AS $item) 
            $item = explode('=', $item);
            $this->fullInfo[$item[0]] = urldecode($item[1]);
        
        $url_encoded_fmt_stream_map = $this->fullInfo['url_encoded_fmt_stream_map'];
        $url_encoded_fmt_stream_map = explode(',', $url_encoded_fmt_stream_map);
        $this->fullInfo['url_encoded_fmt_stream_map'] = [];
        foreach ($url_encoded_fmt_stream_map AS $downloadItem) 
            $downloadInfo = [];
            parse_str($downloadItem, $downloadInfo);
            $this->fullInfo['url_encoded_fmt_stream_map'][] = $downloadInfo;
        

        $adaptive_fmts = $this->fullInfo['adaptive_fmts'];
        $adaptive_fmts = explode(',', $adaptive_fmts);
        $this->fullInfo['adaptive_fmts'] = [];
        foreach ($adaptive_fmts AS $item) 
            $itemInfo = [];
            parse_str($item, $itemInfo);
            $this->fullInfo['adaptive_fmts'][] = $itemInfo;
        

        $this->fullInfo['html'] = file_get_contents("https://www.youtube.com/watch?v=$videoId");
        $this->fullInfo['video_id'] = $videoId;
    
    return $this->fullInfo;


请帮我解决它。谢谢

【问题讨论】:

How can I write a PHP script to download YouTube videos?的可能重复 我的问题是下载失败-禁止 我在帖子中编辑/添加了网站网址,请尝试一下 您好,欢迎来到 Stack Overflow,请阅读如何创建 Minimal, Complete, and Verifiable example 并检查 How to Ask Good Questions,这样您就有机会获得反馈和有用的答案。 【参考方案1】:

由于最新回复与 youtube 的当前结果已过时,我想发布更新。对于使用上述代码的任何人url_encoded_fmt_stream_map 都会引发错误,因为 YouTube 将该参数的值更改为 player_response

下面的代码将输出一个包含 YouTube 视频源网址的 JSON 对象。

<?php
/*
YouTubeLinkSourcer
by digitallysavvy
based on code by [egy.js](https://www.instagram.com/egy.js/);
v0.1
*/
header('Access-Control-Allow-Origin: *');
header('Content-Type: application/json');


function get_error($ErrorExaction)
    $myObj = new stdClass();
    $myObj->error = true;
    $myObj->msg = $ErrorExaction;

    $myJSON = json_encode($myObj,JSON_PRETTY_PRINT);
    echo $myJSON;
    exit;


// pass youtube url via param
if(isset($_GET['ytURL']) && $_GET['ytURL'] != "") 
    // parse the url param to split the string
    parse_str( parse_url( $_GET['ytURL'], PHP_URL_QUERY ), $vars );
    $id = $vars['v']; // get the video id from the v query param 
    $dt = file_get_contents("https://www.youtube.com/get_video_info?video_id=$id&el=embedded&ps=default&eurl=&gl=US&hl=en");
    
    if (strpos($dt, 'status=fail') !== false) 

        $x=explode("&",$dt);
        $t=array(); $g=array(); $h=array();

        foreach($x as $r)
            $c=explode("=",$r);
            $n=$c[0]; $v=$c[1];
            $y=urldecode($v);
            $t[$n]=$v;
        

        $x=explode("&",$dt);
        foreach($x as $r)
            $c=explode("=",$r);
            $n=$c[0]; $v=$c[1];
            $h[$n]=urldecode($v);
        
        $g[]=$h;
        $g[0]['error'] = true;
        echo json_encode($g,JSON_PRETTY_PRINT);

     else 
        // decode the response
        $x=explode("&",$dt);
        $t=array(); $g=array(); $h=array();

        foreach($x as $r)
            $c=explode("=",$r);
            $n=$c[0]; $v=$c[1];
            $y=urldecode($v);
            $t[$n]=$v;
        
        // get the "player_response" field and parse it as JSON
        $player_response = json_decode(urldecode($t['player_response']), true);
        
        // if response is missing streaming data - show an error and exit
        if(!array_key_exists("streamingData",$player_response)) 
          get_error('ops! this video has something wrong! :( '); 
        
        // get reference to the streaming data object
        $streams = $player_response["streamingData"]; 
        // loop through the list and print out all formats
        echo " \"formats\": [";
        foreach ($streams["formats"] as $formats) 
          echo " \"". $formats["qualityLabel"] ."\": \"". $formats["url"] ."\" ,";
        
        echo "], \"adaptiveFormats\": [";
        foreach ($streams["adaptiveFormats"] as $adaptiveFormats) 
            if(array_key_exists("qualityLabel",$adaptiveFormats)) 
                echo " \"". $adaptiveFormats["qualityLabel"] ."\": \"". $adaptiveFormats["url"] ."\" ,";
             else 
                break; // end the loop
            
        
        echo "]";
    
 else 
     get_error("Ops, there is no youtube link!");

使用以下命令调用此脚本:

/YouTubeSourcer.php?ytURL=https://www.youtube.com/watch?v=nMAzchVWTis

【讨论】:

根据 Youtube 的 DTOS,禁止抓取 Youtube 的网站:抓取: 您和您的 API 客户不得也不得鼓励、启用或要求其他人直接或间接地抓取 YouTube 应用程序或 Google 应用程序,或获取抓取的 YouTube 数据或内容。公共搜索引擎只能根据 YouTube 的 robots.txt 文件或在 YouTube 事先书面许可的情况下抓取数据。 因此,我认为您的解决方案不适合本论坛。请善待重新考虑您的帖子。【参考方案2】:

试试这个仅从 youtube 视频 id 获取 Youtube 视频源

    // Get Youtube Source
function getYoutubeVideoSource1($id = 'jNQXAC9IVRw')
    parse_str(file_get_contents("http://youtube.com/get_video_info?video_id=".$id),$info);
    $streams = $info['url_encoded_fmt_stream_map'];
    $streams = explode(',',$streams);
    //dd($streams);
    // store value in array
    $video_stream = array();
    foreach ($streams as $stream)
        parse_str($stream,$data);
        $data = array(
            'type' => $data['type'],
            'quality' => $data['quality'],
            'url' => $data['url'],
        );
        $video_stream[] = (object) $data;
    
    print_r($video_stream);

    //return $video_stream;

在这里,您将获得一系列视频流。

   array:4 [▼
  0 => #216 ▼
    +"type": "video/webm; codecs="vp8.0, vorbis""
    +"quality": "medium"
    +"url": "https://r3---sn-ugp5obax-q5je.googlevideo.com/videoplayback?ipbits=0&ei=qC_9Wa3HD9rcogOXgZuAAw&lmt=1380226535526270&expire=1509786632&sparams=clen%2Cdur%2Cei%2C ▶"
  
  1 => #211 ▶
  2 => #212 ▶
  3 => #218 ▶
]

现在你可以得到这样的视频链接

// Get Youtube Batch Download link
function youtubeBatchDownloadLink($videoId, $format)
    $video_source = getYoutubeVideoSource ($videoId);
    $url = $video_source[$format]->url;
    print_r($url);
    //return $url;

希望对你有帮助

【讨论】:

如果我理解您只是获取有关 youtube 上视频的信息.. 但是有什么方法可以下载吗? 获得下载链接后也可以下载视频。 使用 youtubeBatchDownloadLink() 获取下载链接。 还需要php文件下载脚本。 ***.com/questions/12295604/php-simple-download-script

以上是关于php 中的 Youtube 视频下载器失败 - 禁止的主要内容,如果未能解决你的问题,请参考以下文章

php 从PHP中的URL中提取YouTube视频ID

php 从PHP中的URL中提取YouTube视频ID

php 从PHP中的URL中提取YouTube视频ID

获取 YouTube 视频缩略图并将其与 PHP 一起使用

PHP 管理器 - 下载的文件签名验证失败

在 PHP 中获取带有视频 ID 的 YouTube 视频标题