下载知乎视频并在线播放
下载知乎视频并在线播放
项目地址
下载知乎视频
知乎的视频使用HLS实时流传输协议进行传输.HLS,Http Live Streaming 是由Apple公司定义的用于实时流传输的协议,HLS基于HTTP协议实现,传输内容包括两部分,一是M3U8描述文件,二是TS媒体文件。
1、M3U8文件
用文本方式对媒体文件进行描述,由一系列标签组成。
#EXTM3U#EXT-X-TARGETDURATION:5#EXTINF:5,./0.ts#EXTINF:5,./1.ts#EXTM3U:每个M3U8文件第一行必须是这个tag。#EXT-X-TARGETDURATION:指定最大的媒体段时间长度(秒),#EXTINF中指定的时间长度必须小于或等于这个最大值。该值只能出现一次。#EXTINF:描述单个媒体文件的长度。后面为媒体文件,如./0.ts
2、ts文件
ts文件为传输流文件,视频编码主要格式h264/mpeg4,音频为acc/MP3。
获取答案中的视频链接
知乎视频链接的格式https://www.zhihu.com/video/984740889473818624
访问答案链接,获取链接对应的html文件内容
import request from 'request-promise' import unescape from 'unescape' const TARGET_VIDEO_DIR = `${__dirname}/public/video`
使用正则表达式获取视频链接
const rex = />(https:\/\/www.zhihu.com\/video\/([0-9]+))</ const matchResult = content.match(rex) if (!matchResult) {throw new Error('there is not video exist') } // https://www.zhihu.com/video/984740889473818624 const videoUrl = matchResult[1] // 984740889473818624 const videoHash = matchResult[2]
下载视频链接中对应的m3u8和ts文件
访问获取到的视频链接https://www.zhihu.com/video/984740889473818624, 使用F12查看具体的访问过程,可以发现,知乎对此视频链接的处理如下:
请求
https://lens.zhihu.com/api/videos/984740889473818624
,获取播放列表,结果如下:{ "playlist":{ "ld":{"width": 640, "format": "m3u8", "play_url": "https://vdn.vzuu.com/Act-ss-m3u8-ld/4d2f1b27a0a0417c937af38548310006/135ba0d0-62e7-11e8-8574-0242ac112a1f.m3u8?auth_key=1534147563-0-0-bb23f2e6455b894f0aa1d216afbc0a12&expiration=1534147563&disable_local_cache=0",…}, "hd":{"width": 1280, "format": "m3u8", "play_url": "https://vdn.vzuu.com/Act-ss-m3u8-hd/4d2f1b27a0a0417c937af38548310006/135ba0d0-62e7-11e8-8574-0242ac112a1f.m3u8?auth_key=1534147563-0-0-a0797a8a37c6b316ece393d89a213978&expiration=1534147563&disable_local_cache=0",…}, "sd":{"width": 848, "format": "m3u8", "play_url": "https://vdn.vzuu.com/Act-ss-m3u8-sd/4d2f1b27a0a0417c937af38548310006/135ba0d0-62e7-11e8-8574-0242ac112a1f.m3u8?auth_key=1534147563-0-0-d92ae153e7730835c684202afa3da9d8&expiration=1534147563&disable_local_cache=0",…} }, "title": "", "duration": 19, "cover_info":{ "width": 1280, "thumbnail": "https://pic3.zhimg.com/80/v2-73bb3006d2228ce55d6aade8975e0ade_b.jpg", "height": 2258 }, "type": "video", "id": "984740889473818624", "misc_info":{} }
选择playlist中的某一个列别,使用play_url下载所有ts文件病进行播放
根据以上的步骤,编写实现代码
调用
https://lens.zhihu.com/api/videos/984740889473818624
获取play_urlconst vidoesApi = `https://lens.zhihu.com/api/videos/${videoHash}` // get m3u8 url, just need to get one, and tsFetcher will download all ts files const m3u8Url = JSON.parse(await request(vidoesApi)).playlist.hd.play_url
从play_url下载所有TS文件(使用download-m3u8依赖完成下载)
shell
npm install -g download-m3u8
# simply pass a http link to a m3u8 playlist
download-m3u8 https://bitdash-a.akamaihd.net/content/sintel/hls/playlist.m3u8为了能在程序中自动下载使用child_process中的execSync完成shell命令的调用
typescript
import { execSync } from 'child_process'
execSync(`download-m3u8 ${m3u8Url}`)
console.log('download all ts files done.')至此,所有的ts相关的文件都会保存在
./{http-host}/{filename}
将所有的ts 文件合并成一个大的ts文件
ts文件是以二进制的格式进行存储, 可以以二进制合并的方式直接将所有小的ts文件合并成一个大的ts文件,在linux系统下可以使用cat命令直接完成.
// Get all ts file
const tsFiles = fs.readdirSync(videoDir).filter((value) => {return 'ts' === value.split('.')[1]
})
const sourceFiles = tsFiles.join(' ')
execSync(`cat ${sourceFiles} > ${videoDir}/${name}.ts`)
console.log('merge ts files done.')
将ts文件转成MP4格式的视频文件
将ts文件转换成mp4的工作可以使用mpegts_to_mp4
依赖包完成
import mpegts_to_mp4 from 'mpegts_to_mp4'
mpegts_to_mp4(tsFileName, 'test.mp4', async (err) => {if(err){console.log("Error: "+err)}// remove all ts filesconst downloadRootDir = path.join(videoDir, '../', '../')await rimraf_then(downloadRootDir)console.log("Done converting vids.")
})
html5和Nodejs使用视频流在线播放
基本知识
HTTP status 206(Partial Content)
在传输大容量数据时,通过将数据分分割成多块,让浏览器逐步显示.需要在响应头设置相关信息:
'Content-Range': 'bytes chunkStart-chunkEnd/chunkSize'
'Accept-Ranges': 'bytes'
'Content-Length': chunkSize
'Content-Type': 'video/mp4'
浏览器在请求视频时会自动设置所需的ranges,所以后台需要获取请求头部的ranges信息,返回指定范围的数据
- 5001-10000字节
Range: bytes=5001-10000
- 从5001字节之后的所有数据
Range: bytes=5001-
后台实现
app.get('/video', (req, res) => {const videoName = req.query.nameconsole.log('name', videoName)console.log(req.headers)const videoPath = `${VIDEO_DIR}${videoName}`const videoState = fs.statSync(videoPath) // video file's sizeconst videoSize = videoState.sizelet range = req.headers.rangerange = Array.isArray(range) ? range[0] : rangeif (range) {const parts = range.replace(/bytes=/, '').split('-')const start = parseInt(parts[0], 10)const end = parts[1] ? parseInt(parts[1], 10) : videoSize - 1const chunkSize = (end - start) + 1const file = fs.createReadStream(videoPath, {start, end})const head = { // https://stackoverflow.com/questions/41521272/html5-video-element-not-requesting-end-range // https://stackoverflow.com/questions/48156306/html-5-video-tag-range-header'Content-Range': `bytes ${start}-${end}/${videoSize}`,'Accept-Ranges': 'bytes','Content-Length': chunkSize,'Content-Type': 'video/mp4',}res.writeHead(206, head)file.pipe(res)} else {const head = {'Content-Length': videoSize,'Content-Type': 'video/mp4',}res.writeHead(200, head)fs.createReadStream(videoPath).pipe(res)}
})
前端的简单实现
<video id="videoPlayer" controls><source src="http://localhost:3000/video" type="video/mp4">
</video>
致此,完成简单的知乎视频下载播放的功能.
其他
html自动加载视频
<video id="videoPlayer" controls><source src="http://localhost:3000/video" type="video/mp4">
</video>
const myVideo = document.getElementsByTagName('video')[0]
myVideo.src = `http://${HOST}:${PORT}/video?name=${videoName}`
myVideo.load()
myVideo.play()
axios下载视频
后台实现
app.get('/download', async (req, res) => {
const url = req.query.url
const name = req.query.name
download(url, name).then(videoName => {let currentFile = `${VIDEO_DIR}${videoName}`console.log(currentFile)fs.exists(currentFile, function (exists) {if (exists) {res.download(currentFile)} else {res.set("Content-type", "text/html")res.send("file not exist!")res.end()}})
}).catch(err => {console.log(err)res.statusCode = 500res.end()
})
})
前段实现
// Download the files
const url = window.URL.createObjectURL(new Blob([response.data]))
const link = document.createElement('a')
link.href = url
link.setAttribute('download', videoName)
document.body.appendChild(link)
link.click()
下载知乎视频并在线播放相关推荐
- python实战笔记之(8):下载知乎视频
这篇想写很久了,今天专门搞了搞,现在把用python下载知乎视频的整个流程码下来. (1)目标站点分析 比如这篇知乎文章https://www.zhihu.com/question/279247693 ...
- 服务器在线看视频无法播放,上传到服务器的视频不能在线播放怎么办?
原标题:上传到服务器的视频不能在线播放怎么办? 问题:我们在本地测试视频播放时,常常遇到这种情况,本地测试视频是可以正常播放的,但项目上传服务器后,视频就无法播放了,原因通常有以下几种,原因及解决方案 ...
- 怎么下载知乎视频,怎么下载M3U8,利用FFMpeg下载M3U8并转成mp4格式
昨天一个朋友问我怎么下载知乎视频,这有何难F12,找到视频链接打开就下载了啊.但是,可但是,但可是,我并没有成功. 查了很多资料,知乎使用的是M3U8视频.我还不太懂什么是M3U8,大概就是把视频切成 ...
- python需要花钱下载吗_用Python下载知乎视频,非常实用
原标题:用Python下载知乎视频,非常实用 Python下载知乎视频. # -*- coding: utf-8 -*- """ 下载知乎视频: 依赖: pip inst ...
- android xml mpg格式,急求: android如何对mpg格式视频实现在线播放?
急求: android怎么对mpg格式视频实现在线播放??? 对于3GP格式的视频都直接可以进行播放,但是对mpg格式谈话对话框提示无法播放此视频.是不是mpg格式的还需要我特别进行格式转化呢? 播放 ...
- 上传服务器上的视频不能在线播放的解决方案合集
问题:我们程序员在本地测试视频播放时,常常遇到这种情况,本地测试视频是可以正常播放的,但项目上传服务器后,视频就无法播放了,原因通常有以下几种,原因及解决方案如下: 一.视频编码格式 以MP4为例,虽 ...
- 基于Python SimpleHTTPServer.py的修改脚本:HTTP文件服务器,修正中文目录列表,支持视频文件在线播放
# -*- coding: gbkimport SimpleHTTPServer import BaseHTTPServer import time import SocketServer impor ...
- 趣闻-如何下载知乎视频
打开带视频的知乎链接.比如: 右键查看网页源代码,可以看到一大堆眼花缭乱的代码. Ctrl f 查找 video-box,可以看到后边跟了个链接.class="video-box" ...
- 如何全自动下载知乎上的视频到本地
比如这种 https://zhuanlan.zhihu.com/p/33805972?group_id=946815716536619008&utm_source=wechat_session ...
- android视频恢复播放器,AndroidVideoPlayer在线播放视频
AndroidVideoPlayer在线播放视频 AndroidVideoPlayer在线播放视频,自定义SuperVideoPlayer里面封装了startPlayVideo()播放视频 loadA ...
最新文章
- 元学习(meta learning) 最新进展综述论文,28页pdf
- 修复思维导图mindmanager移动文件位置后打开崩溃
- 对付网络盗贼的三板斧
- php显示发件人地址吗,php – 发件人地址被拒绝
- 牛客题霸 [三个数的最大乘积]C++题解/答案
- Fitness - 05.23
- oracle把两个字段拼接在一起,请问Oracle中两个日期拼接在一起的语句应该怎么写?...
- tiktok+独立站怎么引流?
- 夸大 iPhone 防水功能?苹果遭起诉,曾已被罚 1200 万美元
- 软件核心研发迎来又一春!
- Python 和Java 哪个更适合做自动化测试?
- ffmpeg转码命令
- 揭开,字节跳动全链路压测的实践之路
- C语言计算圆周率小数后10位,计算圆周率Pi(π)值,精确到小数点后10000位 - 圆周率10000位 - C++ 爱好者...
- 西门子PLC程序调试方法
- 纯CSS实现数据上报和HTML验证
- 电子技术基础(三)__电感的感抗_无功功率和电容的容抗_无功功率
- 最新表情包小程序+前后端去授权版/最火表情包小程序源码
- tf.estimator.train_and_evaluate 详解
- 读《大话数据结构》溢彩加强版