PHP解析抖音无水印视频播放地址原理

这次来个重头好戏———抖音无水印播放解析下载。抖音的也是炒鸡简单啦,上图开始分析。

原理分析

习惯性的在浏览器中打开一个分享链接https://v.douyin.com/JFY8sqW/开始访问,访问发生重定向,地址栏里变成了重定向的一大串https://www.iesdouyin.com/share/video/6847790700554177805/?region=CN&mid=6847790811422509838&u_code=0&titleType=title&utm_source=copy_link&utm_campaign=client_share&utm_medium=android&app=aweme
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8OwbM6Uz-1595894735514)(evernotecid://40859371-AF48-4B04-9A39-E177EA4BACC5/appyinxiangcom/16208333/ENResource/p11)]

F12打开控制台调整到手机端访问,打开network XHR请求,发现如图左边的第一个请求比较可疑。果断点开请求看响应,见名知义寻找线索,发现右边的那个地址play_addr比较像要找的播放地址。
啥也不说了,手机模式下访问这个地址,果不其然,真的是视频地址,居然还有抖音logo,这是带水印的播放地址哎,仔细观察下,这个播放地址里有个字符串playwm像似playwatermark的简写,去掉wm试下,哇真的没有水印了,完美,目标已经找到。
是时候好好分析一下这个请求的request了,很显然item_ids是一个参数。拎出来这个请求url,完美获取数据。那关键点开始转义到这个 item_ids字段怎么获取,往地址栏一看,url里面呆着呢,至此,大公告成。
总结归纳一下, 获取重定向地址栏里的类似video_id的字段值6847790700554177805
直接拼接好url后 https://www.iesdouyin.com/web/api/v2/aweme/iteminfo/?item_ids=6847790700554177805 发起请求获取带水印的 播放地址https://aweme.snssdk.com/aweme/v1/playwm/?video_id=v0200fc30000bs43pp80c78p0q1l80gg&ratio=720p&line=0
去掉水印播放url里的wm即可获取到无水印播放地址。

PHP代码实现

首先安装Guzzle库并引入
composer require guzzlehttp/guzzle

require __DIR__.'/vendor/autoload.php';
use GuzzleHttp\Psr7\Stream;

class RemoveWater
{
    protected $headers = [
        'Connection' => 'keep-alive',
        'User-Agent' => 'Mozilla/5.0 (iPhone; CPU iPhone OS 12_1_4 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/16D57 Version/12.0 Safari/604.1'
    ];

    /**
     *  简单请求数据
     */
    static function guzzleRequest($url, $params = [], $timeout, $headers = [])
    {
        $client = new \GuzzleHttp\Client(['timeout' => $timeout, 'headers' => $headers, 'http_errors' => false,]);
        try {
            $data = [];
            if ($headers) {
                $data['headers'] = $headers;
            }
            $jar             = new \GuzzleHttp\Cookie\CookieJar;
            $data['cookies'] = $jar;
            if (!$params) {
                $response = $client->request('GET', $url, $data);
            } else {
                $data ['form_params'] = $params;
                $response             = $client->request('POST', $url, $data);
            }
            $body = $response->getBody();
            if ($body instanceof Stream) {
                $body = $body->getContents();
            }
            $res = json_decode($body, true);
            if ($res) {
                return $res;
            }
            return $body;
        } catch (\GuzzleHttp\Exception\GuzzleException $e) {
            return false;
        }
    }

    function douYin($url)
    {
            $userAgent = $this->headers;
            $client = new \GuzzleHttp\Client();
            $res = $client->request('GET', $url, ['headers' => $userAgent, 'allow_redirects' => false , 'referer' => true]);
            $content = $res->getBody()->getContents();
            preg_match("#video/(.*)?/\?#", $content, $match);
            $itemId = $match[1] ?? '';
            preg_match("#dytk: \"(.*)\"#", $content, $match);
            $dytk      = $match[1] ?? '';
            if (empty($itemId)) {
                $content = self::guzzleRequest($url, [], 2, $userAgent, false);
                $pattern = '#video/([0-9]{1,})/#';
                preg_match($pattern, $content, $match);
                $itemId = $match[1];
            }
            $apiUrl    = "https://www.iesdouyin.com/web/api/v2/aweme/iteminfo/?item_ids=$itemId&dytk=$dytk";
            $content   = self::guzzleRequest($apiUrl, [], 2, $userAgent);
            $videoUrl = $content['item_list'][0]['video']['play_addr']['url_list'][0];
            $videoUrl = str_replace('playwm', 'play', $videoUrl);
            $coverImage     = $content['item_list'][0]['video']['dynamic_cover']['url_list'][0];
            $title = $content['item_list'][0]['desc'] ?? '';
            $bgmSrc = $content['item_list'][0]['music']['play_url']['uri'] ?? '';
            $client = new \GuzzleHttp\Client();
            $jar = new \GuzzleHttp\Cookie\CookieJar;
            $content = $client->request('GET', $videoUrl,[
                'allow_redirects' => false,
                'cookies' => $jar,
                'headers' => $this->headers,
            ])->getBody()->getContents();
            preg_match("#href=\"(.*)\"#", $content, $match);
            $endUrl = $match[1];
            return [
                'video_src' => $endUrl,
                'cover_image' => $coverImage,
                'title' => $title,
                'bgm_src' => $bgmSrc,
            ];
    }
}

$url = $_GET['url'] ?? 'https://v.douyin.com/JFY8sqW/';
$result = (new RemoveWater())->douYin($url);
var_dump($result);
           
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一只码LaJun

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值