在 Phantom.js 中设置超时
setTimeout in Phantom.js
下面的代码想要 Phantom.js 加载页面,点击一个按钮并等待 5 秒,然后 return 输入页面的 HTML 代码。
问题: 但是使用 setTimeout()
创建 5 秒延迟会导致
page.evaluate
函数改为returnnull
回调函数代替HTML.
myUrl = 'http://www.google.com'
var phantom = Meteor.npmRequire('phantom')
phantom.create = Meteor.wrapAsync(phantom.create)
phantom.create( function(ph) {
ph.createPage = Meteor.wrapAsync(ph.createPage)
ph.createPage(function(page) {
page.open = Meteor.wrapAsync(page.open)
page.open(listingUrl, function(status) {
console.log('Page loaded')
page.evaluate = Meteor.wrapAsync(page.evaluate)
page.evaluate(function() {
// Find the button
var element = document.querySelector( '.search-btn' );
// create a mouse click event
var event = document.createEvent( 'MouseEvents' );
event.initMouseEvent( 'click', true, true, window, 1, 0, 0 );
// send click to element
element.dispatchEvent( event );
// Give page time to process Click event
setTimeout(function() {
// Return HTML code
return document.documentElement.outerHTML
}, 5000)
}, function(html) {
// html is `null`
doSomething()
})
})
})
})
用 Meteor.setTimeout()
替换 setTimeout()
会导致另一个错误:
phantom stdout: ReferenceError: Can't find variable: Meteor
page.evaluate()
是 PhantomJS 的沙盒页面上下文。它无权访问外部定义的变量。如果您需要超时,那么您需要对 page.evaluate()
进行两次调用,因为您不能 return 来自异步函数的任何内容 (explanation):
page.evaluate(function() {
...
element.dispatchEvent( event );
}, function() {
setTimeout(function() {
page.evaluate(function() {
return document.documentElement.outerHTML
}, function(html) {
doSomething()
})
}, 5000)
})
您可以通过直接访问定义的内容来缩短代码,而不是使用第二个 page.evaluate()
调用 here:
setTimeout(function() {
page.get("content", function(content) {
doSomething()
})
}, 5000)
这不是一个很好的解决方案,但如果您想做的只是处理按钮点击和表单提交时的页面更改,那么它是可行的。
只需在 page.open() 外部声明函数变量,然后稍后在内部为它们分配页面评估函数。 onLoadFinished 将在页面重新加载并通过单击按钮进行更改后调用,然后您可以再次对其进行评估。
var loadInProgress = false,
jurl = 'http://ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.min.js',
page = require('webpage').create();
// declare variables outside page.open and assign them later inside
var evalPageFunc;
// assign callbacks which will be called by phantom
page.onLoadStarted = function() {
loadInProgress = true;
console.log('load started');
};
page.onLoadFinished = function() {
loadInProgress = false;
console.log('load finished');
if (evalPageFunc) {
// since the page has loaded we can safely evaluate it
var mydata = evalPageFunc();
console.log(mydata);
if (!mydata.havemore) {
phantom.exit();
// or next url
}
}
};
page.open(url, function(status) {
page.includeJs(jurl, function(){
// define your page evaluating functions
evalPageFunc = function(){
return page.evaluate(function() {
var datafromhtml = {}, havemoretoclick = true;
// get your data and perform clicks if you want to
// datafromhtml.somedata = $('stealme').text();
// $("clickme").click();
return {
havemore: havemoretoclick,
data: datafromhtml
};
});
}
var k = evalPageFunc();
});
});
虽然不漂亮,但很管用。
下面的代码想要 Phantom.js 加载页面,点击一个按钮并等待 5 秒,然后 return 输入页面的 HTML 代码。
问题: 但是使用 setTimeout()
创建 5 秒延迟会导致
page.evaluate
函数改为returnnull
回调函数代替HTML.
myUrl = 'http://www.google.com'
var phantom = Meteor.npmRequire('phantom')
phantom.create = Meteor.wrapAsync(phantom.create)
phantom.create( function(ph) {
ph.createPage = Meteor.wrapAsync(ph.createPage)
ph.createPage(function(page) {
page.open = Meteor.wrapAsync(page.open)
page.open(listingUrl, function(status) {
console.log('Page loaded')
page.evaluate = Meteor.wrapAsync(page.evaluate)
page.evaluate(function() {
// Find the button
var element = document.querySelector( '.search-btn' );
// create a mouse click event
var event = document.createEvent( 'MouseEvents' );
event.initMouseEvent( 'click', true, true, window, 1, 0, 0 );
// send click to element
element.dispatchEvent( event );
// Give page time to process Click event
setTimeout(function() {
// Return HTML code
return document.documentElement.outerHTML
}, 5000)
}, function(html) {
// html is `null`
doSomething()
})
})
})
})
用 Meteor.setTimeout()
替换 setTimeout()
会导致另一个错误:
phantom stdout: ReferenceError: Can't find variable: Meteor
page.evaluate()
是 PhantomJS 的沙盒页面上下文。它无权访问外部定义的变量。如果您需要超时,那么您需要对 page.evaluate()
进行两次调用,因为您不能 return 来自异步函数的任何内容 (explanation):
page.evaluate(function() {
...
element.dispatchEvent( event );
}, function() {
setTimeout(function() {
page.evaluate(function() {
return document.documentElement.outerHTML
}, function(html) {
doSomething()
})
}, 5000)
})
您可以通过直接访问定义的内容来缩短代码,而不是使用第二个 page.evaluate()
调用 here:
setTimeout(function() {
page.get("content", function(content) {
doSomething()
})
}, 5000)
这不是一个很好的解决方案,但如果您想做的只是处理按钮点击和表单提交时的页面更改,那么它是可行的。 只需在 page.open() 外部声明函数变量,然后稍后在内部为它们分配页面评估函数。 onLoadFinished 将在页面重新加载并通过单击按钮进行更改后调用,然后您可以再次对其进行评估。
var loadInProgress = false,
jurl = 'http://ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.min.js',
page = require('webpage').create();
// declare variables outside page.open and assign them later inside
var evalPageFunc;
// assign callbacks which will be called by phantom
page.onLoadStarted = function() {
loadInProgress = true;
console.log('load started');
};
page.onLoadFinished = function() {
loadInProgress = false;
console.log('load finished');
if (evalPageFunc) {
// since the page has loaded we can safely evaluate it
var mydata = evalPageFunc();
console.log(mydata);
if (!mydata.havemore) {
phantom.exit();
// or next url
}
}
};
page.open(url, function(status) {
page.includeJs(jurl, function(){
// define your page evaluating functions
evalPageFunc = function(){
return page.evaluate(function() {
var datafromhtml = {}, havemoretoclick = true;
// get your data and perform clicks if you want to
// datafromhtml.somedata = $('stealme').text();
// $("clickme").click();
return {
havemore: havemoretoclick,
data: datafromhtml
};
});
}
var k = evalPageFunc();
});
});
虽然不漂亮,但很管用。