【问题标题】:how to wait for element visibility in phantomjs如何等待phantomjs中的元素可见性
【发布时间】:2013-05-24 07:39:49
【问题描述】:

用户点击此链接:

<span onclick="slow_function_that_fills_the_panel(); $('#panel').show();">

现在我在 phantomjs 中模拟点击:

page.evaluate(
  function() { $("#panel").click(); }
);
console.log('SUCCESS');
phantom.exit();

Phantom 在慢速函数结束执行并且 DIV 变得可见之前退出。如何实现等待?

【问题讨论】:

  • 愚蠢的解决方案是 setTimeout()

标签: javascript jquery phantomjs


【解决方案1】:

这是 Cyber​​maxs 的回答:

function waitFor ($config) {
    $config._start = $config._start || new Date();

    if ($config.timeout && new Date - $config._start > $config.timeout) {
        if ($config.error) $config.error();
        if ($config.debug) console.log('timedout ' + (new Date - $config._start) + 'ms');
        return;
    }

    if ($config.check()) {
        if ($config.debug) console.log('success ' + (new Date - $config._start) + 'ms');
        return $config.success();
    }

    setTimeout(waitFor, $config.interval || 0, $config);
}

使用示例:

waitFor({
    debug: true,  // optional
    interval: 0,  // optional
    timeout: 1000,  // optional
    check: function () {
        return page.evaluate(function() {
            return $('#thediv').is(':visible');
        });
    },
    success: function () {
        // we have what we want
    },
    error: function () {} // optional
});

使用配置变量会容易一些。

【讨论】:

  • 谢谢!我花了两天时间尝试了六种其他可靠检查表单是否已提交的方法(而不是盲目地希望setTimeout),这是唯一对我来说完美无缺的方法。 +1
【解决方案2】:

默认情况下,PhantomJS 异步运行,导致出现上述问题(脚本在结果准备好之前完成)

但是,没有什么可以阻止您以同步方式使用它。

只需在 while 循环中使用 phantom.page.sendEvent('mousemove')。这将继续循环通过事件泵,直到 webkit 引擎加载您的页面或处理任何必要的浏览器事件。

var page = require('webpage').create();

// Step 1: View item
page.open('http://localhost/item3324.php');
do { phantom.page.sendEvent('mousemove'); } while (page.loading);
page.render('step1-viewitem.png');

// Step 2: Add to cart
page.evaluate(function() {$('#add-to-cart').click(); });
do { phantom.page.sendEvent('mousemove'); } while (page.loading);
page.render('step2-viewcart.png');

// Step 3: Confirm contents
page.evaluate(function() {$('#confirm-cart').click(); });
do { phantom.page.sendEvent('mousemove'); } while (page.loading);
page.render('step3-confirm.png');

请注意,page.loading 也可以是任何其他布尔条件,例如:

do { phantom.page.sendEvent('mousemove'); } 
while (page.evaluate(function() {return $("#panel").is(":visible");}));

我在处理 triflejs.org 项目(Internet Explorer 版本的 phantom)时发现了这种方法,试图在 PhantomJS 环境中模拟对 trifle.wait(ms) 的调用。

【讨论】:

  • phantom.page.sendEvent('mousemove')可以在手机页面工作吗?
  • @FengYu 确定。 mousemove 是使用正确的事件。 Phantom(就像你的桌面浏览器)不知道它是一个移动页面。它所知道的只是它打开一个网页并呈现它。
  • 我可以在while循环中删除page.sendEvent('mousemove')吗?
  • @FengYu 如果您删除sendEvent('mousemove'),您将进入一个无限循环——即浏览器状态永远不会改变。 Phantom 使用mousemove 事件来触发一个事件循环,该循环执行一系列事情,例如加载、渲染 dom、检查事件和垃圾回收。
  • 我在使用 pohantomjs 时遇到了一些问题。但我不知道这是不是因为我使用了sendEvent('mousemove')。这是我的帖子链接:stackoverflow.com/questions/39993391/….
【解决方案3】:

对于这种情况,我的方法是等到“某事”完成或为真。 我强烈建议你测试waitfor.js

demo.html

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <script src="http://code.jquery.com/jquery-1.9.1.js"></script>
    <title>Test</title>
</head>
<body id="body">

    <div id="thediv">Hello World !</div>

    <script type="text/javascript">
        $('#thediv').hide();
        setTimeout(function () {
            $('#thediv').show();
        }, 3000);

    </script>
</body>
</html>

demoscript.js

var page = require('webpage').create();
var system = require('system');

function waitFor(testFx, onReady, timeOutMillis) {
    var maxtimeOutMillis = timeOutMillis ? timeOutMillis : 5000, //< Default Max Timout is 5s
        start = new Date().getTime(),
        condition = false,
        interval = setInterval(function () {
            if ((new Date().getTime() - start < maxtimeOutMillis) && !condition) {
                // If not time-out yet and condition not yet fulfilled
                condition = (typeof (testFx) === "string" ? eval(testFx) : testFx()); //< defensive code
            } else {
                if (!condition) {
                    // If condition still not fulfilled (timeout but condition is 'false')
                    //console.log("'waitFor()' timeout");
                    typeof (onReady) === "string" ? eval(onReady) : onReady();
                    clearInterval(interval);
                    //phantom.exit(1);
                } else {
                    // Condition fulfilled (timeout and/or condition is 'true')
                    console.log("'waitFor()' finished in " + (new Date().getTime() - start) + "ms.");
                    typeof (onReady) === "string" ? eval(onReady) : onReady(); //< Do what it's supposed to do once the condition is fulfilled
                    clearInterval(interval); //< Stop this interval
                }
            }
        }, 500); //< repeat check every 500ms
};

if (system.args.length != 1) {
    console.log('invalid call');
    phantom.exit(1);
} else {
    //adapt the url to your context
    page.open('http://localhost:40772/demo.html', function (status) {
        if (status !== 'success') {
            console.log('Unable to load the address!');
            phantom.exit();
        } else {
            waitFor(
                function () {
                    return page.evaluate(function () {
                        return $('#thediv').is(':visible');
                    });
                },
                function () {
                    page.render('page.png');
                    phantom.exit();
                }, 5000);
        }
    });
}

此脚本每 500 毫秒评估一次 $('#thediv').is(':visible')(经典 Jquery 代码)以检查 div 是否可见。

【讨论】:

【解决方案4】:

在 page.evaluate() 中,使用 self.loading 属性来测试完成度 ....

var fs = require('fs');
path = '/path/to/file.html';
address = 'http://google.com';    

page.open(address, function (status) {
    if (status !== 'success') {
        console.log('Unable to access page');
    } else {
        var p = page.evaluate(function () {
            if(!self.loading){ // ah, such beauty
              return document.documentElement.outerHTML;
            }
        });
    fs.write(path, p, 'w');
    }
    phantom.exit();
});     

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-05-20
    • 1970-01-01
    • 2021-01-03
    • 2017-08-14
    • 1970-01-01
    • 1970-01-01
    • 2016-05-09
    • 2019-10-21
    相关资源
    最近更新 更多