javascript 如何在 PhantomJS 中等待页面准备就绪?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/24143044/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How can I wait for the page to be ready in PhantomJS?
提问by Mridang Agarwalla
I'm using PhantomJS to log into a site an do something. The site used OAuth for logging in. Clicking on the "Login" button on the, takes you to the OAuth service. There you enter your credentials and clicking "Submit", you get redirected back to the original site. My script works fine but relies on timeouts which doesn't seem too robust.
我正在使用 PhantomJS 登录站点并执行某些操作。该站点使用 OAuth 进行登录。单击 上的“登录”按钮,将您带到 OAuth 服务。在那里您输入您的凭据并单击“提交”,您将被重定向回原始站点。我的脚本工作正常,但依赖于看起来不太健壮的超时。
How can I rewrite this code so that instead of using setTimeout
, I can wait until the page is ready. I often see errors that the page isnt' ready and therefore jQuery isn't initialized.
我怎样才能重写这段代码,而不是使用setTimeout
,我可以等到页面准备好。我经常看到页面未准备就绪的错误,因此 jQuery 未初始化。
I'm not too good with Javascript so an example would be helpful. This is what I've hacked together after a ton of Googling. Here's my code:
我对 Javascript 不太好,所以举个例子会有帮助。这是我在大量谷歌搜索后一起破解的。这是我的代码:
var page = require('webpage').create();
var system = require('system');
page.settings.resourceTimeout = 10000;
page.onResourceTimeout = function(e) {
console.log("Timed out loading resource " + e.url);
};
page.open('https://mysite.com/login', function(status) {
if (status !== 'success') {
console.log('Error opening url');
phantom.exit(1);
} else {
setTimeout(function() {
console.log('Successfully loaded page');
page.evaluate(function() {
$("#submit-field").click(); //Clicking the login button
});
console.log('Clicked login with OAuth button');
setTimeout(function() {
console.log('Addding the credentials');
page.evaluate(function() {
document.getElementById("username").value = '[email protected]';
document.getElementById("password").value = 'P@ssw0rd';
document.getElementById("Login").click();
});
console.log('Clicked login button');
setTimeout(function() {
//Inject some jQuery into the page and invoke that here
console.log('Clicked the export button');
}, 15000);
}, 15000);
});
}
});
回答by Mridang Agarwalla
It seems that the only way to do this was to use callbacks from the DOM to PhantomJS.
似乎唯一的方法是使用从 DOM 到 PhantomJS 的回调。
var page = require('webpage').create();
var system = require('system');
page.onInitialized = function() {
page.onCallback = function(data) {
console.log('Main page is loaded and ready');
//Do whatever here
};
page.evaluate(function() {
document.addEventListener('DOMContentLoaded', function() {
window.callPhantom();
}, false);
console.log("Added listener to wait for page ready");
});
};
page.open('https://www.google.com', function(status) {});
回答by Daishi
An alternate method would be to extend the phantomjs waitfor.js
example.
另一种方法是扩展 phantomjswaitfor.js
示例。
I use this personnal blend of method.
This is my main.js
file:
我使用这种个人混合的方法。这是我的main.js
文件:
'use strict';
var wasSuccessful = phantom.injectJs('./lib/waitFor.js');
var page = require('webpage').create();
page.open('http://foo.com', function(status) {
if (status === 'success') {
page.includeJs('https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.1/jquery.min.js', function() {
waitFor(function() {
return page.evaluate(function() {
if ('complete' === document.readyState) {
return true;
}
return false;
});
}, function() {
var fooText = page.evaluate(function() {
return $('#foo').text();
});
phantom.exit();
});
});
} else {
console.log('error');
phantom.exit(1);
}
});
And the lib/waitFor.js
file (which is just a copy and paste of the waifFor()
function from the phantomjs waitfor.js
example):
和lib/waitFor.js
文件(它只是waifFor()
phantomjswaitfor.js
示例中函数的复制和粘贴):
function waitFor(testFx, onReady, timeOutMillis) {
var maxtimeOutMillis = timeOutMillis ? timeOutMillis : 3000, //< Default Max Timout is 3s
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");
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 condi>
clearInterval(interval); //< Stop this interval
}
}
}, 250); //< repeat check every 250ms
}
This method is not asynchronous but at least am I assured that all the resources were loaded before I try using them.
这种方法不是异步的,但至少我确信在我尝试使用它们之前所有资源都已加载。