通过SlimerJS触发键盘事件使优酷视频快进(问题未解决)

来源:互联网 发布:μtorrent mac 编辑:程序博客网 时间:2024/05/02 02:36

需求

我想下载视频网站的视频,但是现在的视频网站不提供视频下载的链接。如果我们分析网页的源码,也许也不会发现视频的地址(网页源码太长,我没有分析过,我只是猜测网页中没有视频的链接)。
通过FireFox的FireBug工具,我能获得浏览器向视频服务器下载视频文件的请求,那么我们能不能用程序来获得这些视频文件的地址,然后自动化地下载它呢?答案是肯定的。

解决方案

我想通过SlimerJS打开一个视频网站,通过Python监听网卡的数据包,将所有HTTP请求截获下来,分析HTTP请求的请求头,将请求头带mp4,flv的请求路径截获下来,因为这些请求就是视频文件的请求。那我们可以用这些请求来获得视频。

我的前2篇博文已经讲解了原理,1.获取网页中的视频下载地址(利用抓包), 2.获取网页中的视频下载地址(用headless browser), 还有源码在github上,源码现在只是实现了一个tornado的服务器,来接受post过来的url,url是我们需要下载的视频的视频页面。tornado服务器收到请求后,会开一个线程,用SlimerJS打开那个视频页面,再开一个线程来监听网卡上的数据。用户下次再带着那个url请求访问tornado服务器,如果视频下载完成了就返回结果,否则返回In progress提示用户晚点再来。

改进方案

因为SlimerJS打开网页视频后,就任由其播放,播放速度较慢,我们需要等待视频播放完了才能将所有视频下载下来。如果我们的网络带宽够大,视频很快就缓冲好了,我们可以快进,让网页去缓冲后面的内容。那么我就想到了让SlimerJS去触发快进的事件。
通过观察,点击播放窗口后,可以按键盘的右箭头来进行快进。

问题

理想太丰满,现实很骨感。那么我们怎么来模拟键盘的右箭头呢?通过查SlimerJS(Phantomjs)的文档可以知道

var page = require("webpage").create()page.sendEvent("keypress", page.event.key.Right, null, null, null); 

sendEvent可以发送键盘事件,但是它发送的键盘事件是发送到document下的。元素监听的keydown事件都不会触发。

实验:

html页面如下

<!DOCTYPE html><html lang="en"><head>    <meta charset="UTF-8">    <title>Title</title></head><body>    <div id="divId" style="width: 200px; height: 200px; background-color: #0000cc" >        <article>            <p style="background-color: #1cc09f">hello</p>            <p style="background-color: #1cc09f">hello</p>        </article>    </div>    <a>        aaaaaa        <p>hello</p>    </a>    <input type="text" id="inputId" name=""></body><script src="./jquery.min.js"></script><script>    $("div").click(function (e) {        console.log('click div');        //alert("click div");    });    $("p").click(function (e) {        console.log('click p');        //alert("click p");        //return false; // 使得div的点击事件消失    });    $(document).keydown(function(event){        console.log("doc keydown");        console.log(event.keyCode);    });     $(document).keypress(function(event){        console.log("doc keypress");        console.log(event.keyCode);    });     $("divId").keydown(function(){        console.log("div keydown")    });    $("divId").keypress(function(){        console.log("div keypress")    });    $("#inputId").keydown(function(event){        console.log("input keydown");    });     $("#inputId").keypress(function(event){        console.log("input keypress");    });  </script></html>
var page = require('webpage').create();    var videoUrl = "click_test.html" //上面的那个页面 page.open(videoUrl , function () {}//通过这个函数监听浏览器的控制台输出page.onConsoleMessage = function (msg) {    console.log('Page console msg: ' + msg);};window.setInterval(function(){    page.sendEvent('keypress', page.event.key.Space, null, null, null);    page.sendEvent('keydown', page.event.key.Space, null, null, null);    console.log("page key press");}, 1000);

输出结果是:

...Page console msg: doc keypressPage console msg: 0Page console msg: doc keydownPage console msg: 32page key press...

我们回去看页面的脚本,我们可以发现我们监听的keypress事件有document,div,input这三个。但是只有document的事件被触发了。那么我们怎么让我们的子元素的keypress事件触发呢?
我们通过page.evaluate()函数来获取网页的元素,来触发元素的事件。

var page = require('webpage').create();    var videoUrl = "click_test.html" //上面的那个页面 page.open(videoUrl , function () {    page.includeJs("jquery.min.js", function(){        window.setInterval(function(){            page.evaluate(function() {                console.log("in evaluate function");                                   var ev = document.createEvent("KeyboardEvent");                ev.initKeyEvent("keydown",       // typeArg,                                                                              true,             // canBubbleArg,                                                                           true,             // cancelableArg,                                                                          null,             // viewArg,  Specifies UIEvent.view. This value may be null.                        false,            // ctrlKeyArg,                                                                                  false,            // altKeyArg,                                                                           false,            // shiftKeyArg,                                                                         false,            // metaKeyArg,                                                                           39,               // keyCodeArg,                                                                          0);              // charCodeArg);                //document.querySelector("a").dispatchEvent(ev);                document.getElementById('divId').dispatchEvent(ev);                document.getElementById('inputId').dispatchEvent(ev);                //page.sendEvent('keypress', page.event.key.Right, null, null, null);            });        }, 5000);    });});

输出的结果如下:

...Page console msg: in evaluate functionPage console msg: doc keydownPage console msg: 39Page console msg: input keydownPage console msg: doc keydownPage console msg: 39...

这里我对input,div这两个元素发送了keydown事件,但是,doc捕获了了2此,input捕获了一次。这是因为一般的div不能触发keydown事件。

对优酷视频网站触发快进事件

通过观察,打开优酷视频网站之后,点击右方向键,页面向右移动。鼠标点击视频之后,再点击右方向键,视频就可以快进了。

猜想

鼠标点击视频之后,focus到视频的元素,键盘事件传到视频元素,触发快进。
figure1
我将键盘事件发给这个flash播放器,可是没有效果。

document.getElementById('movie_player').dispatchEvent(ev);

到底是为什么呢?我查看了优酷的注册事件,键盘事件就那么4个
figure2

keydown:1.(function (t){t=t||B.event;var e=t.target||t.srcElement;a(e,t)})2.(function(t) {    if (y.railslocked && 0 == y.page.maxh) return !0;    t = t ? t : window.e;    var e = y.getTarget(t);    if (e && /INPUT|TEXTAREA|SELECT|OPTION/.test(e.nodeName)) {        var n = e.getAttribute("type") || e.type || !1;        if (!n || !/submit|button|cancel/i.tp) return !0    }    if (l(e).attr("contenteditable")) return !0;    if (y.hasfocus || y.hasmousefocus && !a || y.ispage && !a && !r) {        var i = t.keyCode;        if (y.railslocked && 27 != i) return y.cancelEvent(t);        var o = t.ctrlKey || !1,            s = t.shiftKey || !1,            c = !1;        switch (i) {            case 38:            case 63233:                y.doScrollBy(72), c = !0;                break;            case 40:            case 63235:                y.doScrollBy(-72), c = !0;                break;            case 37:            case 63232:                y.railh && (o ? y.doScrollLeft(0) : y.doScrollLeftBy(72), c = !0);                break;            case 39:            case 63234:                y.railh && (o ? y.doScrollLeft(y.page.maxw) : y.doScrollLeftBy(-72), c = !0);                break;            case 33:            case 63276:                y.doScrollBy(y.view.h), c = !0;                break;            case 34:            case 63277:                y.doScrollBy(-y.view.h), c = !0;                break;            case 36:            case 63273:                y.railh && o ? y.doScrollPos(0, 0) : y.doScrollTo(0), c = !0;                break;            case 35:            case 63275:                y.railh && o ? y.doScrollPos(y.page.maxw, y.page.maxh) : y.doScrollTo(y.page.maxh), c = !0;                break;            case 32:                y.opt.spacebarenabled && (s ? y.doScrollBy(y.view.h) : y.doScrollBy(-y.view.h), c = !0);                break;            case 27:                y.zoomactive && (y.doZoom(), c = !0)        }        if (c) return y.cancelEvent(t)    }})3.(function (t){var e=t.ctrlKey||!1;e&&(y.wheelprevented=!0)})keyup:(function (t){var e=t.ctrlKey||!1;e||(y.wheelprevented=!1)})

这里只有第2个函数详细一点,那我们仔细看看第二个函数的代码,可是也没有发现它监控如何处理快进的,只是处理了怎么去左右上下滑动。我现在就卡在如何触发快进的功能了!
如何触发快进功能是我接下来的需要实现的目标。

0 0
原创粉丝点击