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

需求

我想下载视频网站的视频,但是现在的视频网站不提供视频下载的链接。如果我们分析网页的源码,也许也不会发现视频的地址(网页源码太长,我没有分析过,我只是猜测网页中没有视频的链接)。
通过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 keypress
Page console msg: 0
Page console msg: doc keydown
Page console msg: 32
page 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 function
Page console msg: doc keydown
Page console msg: 39
Page console msg: input keydown
Page console msg: doc keydown
Page 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个函数详细一点,那我们仔细看看第二个函数的代码,可是也没有发现它监控如何处理快进的,只是处理了怎么去左右上下滑动。我现在就卡在如何触发快进的功能了!
如何触发快进功能是我接下来的需要实现的目标。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值