如何在客户端重定向发生后才结束PhantomJS脚本

时间:2012-10-03 14:33:24

标签: phantomjs

我正在努力将PhantomJS无头浏览器集成到我的项目中(目前使用的是1.6版本)。在大多数情况下,它在完成我需要完成的工作方面做得很好。但是,WebPage.open()调用的方式的异步性质,以及在某些时候调用phantom.exit()的需要,使得当您无法预测它们的去向时,处理客户端重定向变得棘手去吧。

我所追求的只是在任何元刷新(导致不同的页面)之后调用phantom.exit()的方法,并且已经执行了与onload事件相关的JavaScript重定向。我可以看到为什么这是一个问题,因为理论上客户端重定向可以在页面加载后的任意秒数发生,并且我不能简单地要求只有在没有更多重定向的情况下才能退出发生。现在,我能想到的最好的解决方案是:a)手动检测页面上元刷新元素的存在并自己处理,b)使用setInterval()来节省一些时间(例如,1-在调用phantom.exit()之前经过1.5秒)。基本上看起来像这样:

var page = require('webpage').create();
var visitComplete = false;
var url = "http://some.url";
var pageOpenedTime;
setInterval(function() {
    if (visitcomplete && typeof pageOpenedTime != 'undefined' &&
        new Date() - pageOpenedTime >= 1500)
    {
        phantom.exit();
    }
), 1000);
page.open(url, function() {
    pageOpenedTime = new Date();
    if (!hasMetaRefresh(page)) {
        visitComplete = true;
    }
});

function hasMetaRefresh(page) {
    // Query the DOM here to detect meta refresh elements
}

有更好的想法吗?

编辑:我应该提一下,我的第一个想法是,当执行与初始页面加载相关联的JavaScript时,可能会有一个PhantomJS事件被触发,但onLoadFinished回调似乎先于任何页内执行JavaScript,包括onload事件。我还做了一些关于我可能需要等待多少时间间隔的测试,虽然1000 ms足够长时间以便在一个小的测试页面中执行JavaScript重定向(通过body onload事件),但100 ms还不够长。

3 个答案:

答案 0 :(得分:8)

我在加载使用Optimizely的网页时遇到了同样的问题,而且变体是location.href重定向。

我现在在“renderPage”函数中使用onNavigationRequest回调。那些优化重定向不再阻塞,我不需要任意超时。

var webpage = require('webpage');
var page = null;

var renderPage = function (myurl) {
    page = webpage.create();

    page.onNavigationRequested = function(url, type, willNavigate, main) {
        if (main && url!=myurl && url.replace(/\/$/,"")!=myurl&& (type=="Other" || type=="Undefined") ) {
        // main = navigation in main frame; type = not by click/submit etc

            log("\tfollowing "+myurl+" redirect to "+url)
            myurl = url;
            page.close();
            renderPage(url); // rerun this function wit the new URL
        }
    }; // on Nav req

    page.open(myurl, function(status) {
        if (status==="success") {
            page.render("screenshot.jpg");
        } else {
            page.close();
        }
    }); // page open
} // render page


renderPage("http://some.domain.com");

请参阅文档:http://phantomjs.org/api/webpage/handler/on-navigation-requested.html

答案 1 :(得分:0)

我有想法为此目的使用模拟计时器。假设我们在页面中包含"a mocked timer"。这样,您可以快进时间以避免js空闲时间。请参阅GitHub页面上的示例。

这只是一种让事情更快发生的方法,但正如您所料,不可能确定将来是否会触发重定向事件。

答案 2 :(得分:0)

我已经查看了phantomjs重定向处理的各种示例:运气不好。

暂时没有普遍的解决方法。如果你修补一些脚本 as suggested here,在其他情况下会失败,例如旁边使用location.href,使用javascript重定向。我还没有测试过身体。在这里和那里打了几笔钱之后,我放弃了。

我只是用“重”Selenium触发的firefox来解决我的问题。如果你需要加载很多页面,而不是重启firefox,只需使用webdriver.delete_all_cookies()清理一些捕获。它给了我可靠的结果(我需要做屏幕截图,下载html,得到最终的网址,以及更多)与phantomjs比较。