某种程度上说,这个工具写得并不成功,适用性较差,不过过程中遇到的许多问题还是比较有探讨价值的,所以分享出来以供参考和交流。
【需求说明】
关于直播视频的下载,网上可以搜到一些,比如用Fiddler脚本抓包ts保存到本地再合并,但这些方式对小白而言太难了,所以就想着写个傻瓜化的工具。程序的界面设计如下。
界面比较简单,左侧可以设置“直播地址、下载目录、保存频率”以及“请求头user-agent”;右侧是直播视频展示区(iframe标签)。
【踩坑01】
此处以百度为例,当试图在iframe中打开百度页面时,报了个错:“Refused to display [URL] in a frame because it set 'X-Frame-Options' to 'sameorigin'.”
X-Frame-Options 响应头是用来给浏览器指示允许一个页面可否在 <frame>、<iframe>、<embed> 或者 <object> 中展现的标记。
可选值 | 作用 |
DENY | 该页面不允许在frame中展示 |
SAMEORIGIN | 该页面可以在相同域名页面的frame中展示 |
ALLOW-FROM | 该页面可以在指定来源的frame中展示 |
ALLOWALL | 该页面允许全部来源域名的frame展示 |
根据这个标识的特点,修改思路便有了:当网络请求响应头返回时对其中的该标识的值进行修改,修改后再嵌套就可规避该错误。相关代码如下
let filters = {urls: ['*://*/*']}session.defaultSession.webRequest.onHeadersReceived(filters, (details, callback) => {details.responseHeaders['X-Frame-Options'] = 'AllowAll'callback({cancel: false, responseHeaders: details.responseHeaders})})
【踩坑02】
此处以抖音直播为例,当使用iframe打开时,报了错“Refused to frame 'https://live.douyin.com/' because an ancestor violates the following Content Security Policy directive: "frame-ancestors live.ixigua.com live.ixigua.com www.ixigua.com activity.douyin.com creator.douyin.com".”
这是因为响应头中设置了内容安全策略,该标识限制了iframe嵌套需要遵循的规则。
Content-Security-Policy字段有若干指令,可以设置指定的策略允许的源。其值的格式为: [指令] <source> ...; [指令] <source> ...;...
指令 | 限制范围 |
frame-ancestors | <frame>,<iframe>,<object>,<embed>或<applet> |
worker-src | Worker SharedWorker ServiceWorker |
script-src | <script> |
… | … |
这个标识和之前的标识类似,修改思路:当网络请求响应头返回时对其中的该标识的值进行修改,修改后再嵌套就可规避该错误。相关代码如下
details.responseHeaders['content-security-policy'] = ''
【踩坑03】
有的网站只允许在微信环境中进行访问,这个分情况,如果只是微信的user-agent校验可以通过修改请求头&本地标识来解决;如果是页面代码逻辑控制的,便没太好的办法(修改原始js数据会破坏业务逻辑,也超出了本程序傻瓜化的初衷)。
修改请求头的user-agent代码:
session.defaultSession.webRequest.onBeforeSendHeaders(filters, (details, callback) => {details.requestHeaders['User-Agent'] = [微信user-agent]callback({cancel: false, requestHeaders: details.requestHeaders})})
修改程序的navigator.userAgent代码:
mainWindow.loadURL('app://./index.html', {userAgent: [微信user-agent]})
【踩坑04】
通过Electron拦截网络请求时,在数据返回的各个阶段都无法拿到响应数据的responseBody,更尴尬的是,其它的数据都有,唯独没有body体。网上搜了很久,资料很少,没有找到有效的办法。
所以,退而求其次,当接口响应数据返回以后,用fetch再请求一次资源(还好有浏览器缓存,所以基本上也还凑合)。
相关代码:
this.tsIndex = 0let filters = {urls: ['*://*/*']}session.defaultSession.webRequest.onCompleted(filters, (details) => { let baseUrl = details.url.split('?')[0] if (/\.ts$/.test(baseUrl) && !this.downloadDict[baseUrl]) { let index = this.tsIndex this.tsIndex++ this.downloadDict[baseUrl] = 1 console.log(index, details.url) fetch(details.url, {method: 'get', responseType: 'arraybuffer'}).then(res => { return res.arrayBuffer() }).then((ab) => { this.dataList[index] = ab }) }})
【功能测试】
测试平台:芒果TV、百度直播、抖音直播
测试结果:芒果TV可以正常抓取;百度直播抓取到的视频数据不能播放;抖音直播抓取不到数据。
在刚刚结束的一场NBA总决赛中,猛龙114-110战胜勇士,大比分4-2获得系列赛胜利,获得了2018-19赛季NBA总冠军。
这是猛龙队史首座总冠军奖杯。
本赛季季后赛中,猛龙4-1淘汰魔术,4-3淘汰76人,4-2淘汰雄鹿,在总决赛中4-2战胜勇士,获得最终的总冠军。
(
今日,根据
他写道“将您带回344天前,去年的4月12日,猛龙季后赛首轮的第一场对阵魔术的比赛。我们将重播猛龙历史性的夺冠之路。TSN与Sportsnet将在24天内交替播出24场比赛,第一场将在东部时间今天晚上8点播出。”
(
1.需要使用新应用以打开此bytedance链接
问题弹窗
问题描述:使用直播下载工具访问抖音直播地址时报上述错误
问题原因:之前编写程序时,默认设置的 user-agent 是模拟手机微信的,导致抖音以为用户是使用手机在访问,于是直播地址尝试通过自定义协议来调用字节跳动的相关APP(猜测bytedance应该是字节跳动APP的自定义协议名称)。但电脑上并不存在相关APP,找不到打开该链接的应用程序,所以就给出了上述提示。
验证方法:在常驻工具栏中修改请求头中的 user-agent,将其修改为电脑浏览器的值(随意复制一个就行),即可绕过上述错误。
验证方法
注意事项:
1)虽然该问题可以绕过,但是因为直播下载工具当初编写时,没支持抖音直播(事实上当时只试了芒果TV尴尬),所以即便绕过上述错误,也还是不能下载(后续我再对其进行改进)。
2)如果现在想下载抖音直播,可以在网站控制台中找到一个后缀为flv的地址(在网络面板中可以看到,随着直播的进行,它一直在加载数据),这个便是直播的地址,你可以直接在浏览器地址栏中访问它进行下载,因为是直播地址,所以它会一直持续下载,如果中间你想停止它,可以随时暂停下载,暂停后将文件拖动到播放器中即可播放。
控制台寻找flv地址
下载并播放flv
2.找不到该直播
问题
问题描述:使用直播下载工具访问快手直播地址时报上述错误
问题原因:直接原因不明。
播放方法:
1)与问题一相同,将user-agent改为电脑端浏览器的(但此时访问会发现白屏,这是因为快手网页设置了Content-Security-Policy属性,对iframe的嵌套规则做了限制);
2)在响应头中将 Content-Security-Policy 设置为空(响应头中的字段是区分大小写的,需要与网站保持一致)。
修改响应头
下载方法:
快手与抖音下载方法相同。
3.BL页面白屏
问题
问题描述:使用直播下载工具访问B直播地址时白屏
问题原因:直接原因还是因为user-agent,调试时发现有个手机端的js文件一直加载失败。
播放方法:像第一个问题一样修改user-agent之后即可访问。
下载方法:使用的数据传输方式与前两个一样都是flv,但是如果直接下载会报403;经过调试,发现它校验了请求头的Referer,所以需要借助抓包工具来下载。
(1)2022lol世界赛程时间表赛程:入围赛:2022年9月29...
(1)2022女篮世界杯赛程表时间女篮联赛2022赛程表如下:小组...
1、cba辽宁2023年赛程表年CBA联赛将于10月初正式开幕,辽...
(1)英雄联盟2021总决赛LPL代表队一览1、S11全球总决赛L...
(1)女排世锦赛2022具体时间1、女排世锦赛2022年时间是9月...