phantomjs api文档
2021-07-03 04:07
标签:系统路径 标记 requested 可靠 ctr 垃圾回收机制 其他 转化 pass phantomjs实现了一个无界面的webkit浏览器。虽然没有界面,但dom渲染、js运行、网络访问、canvas/svg绘制等功能都很完备,在页面抓取、页面输出、自动化测试等方面有广泛的应用。 详细文档 下载phantomjs(官方下载,下载失败请访问另一个下载点)。解压到任意目录,并将包含phantomjs.exe的目录添加到系统路径。 如果要借助phantomjs进行无头测试,请参考各个测试框架的说明,或者参考phantomjs的官方文档:http://phantomjs.org/headless-testing.html。 这个例子简单地展示了通过phantom访问baidu.com,并输入html内容。使用方式就像使用node运行js代码一样。在phantom运行时,它会向当前代码运行环境注入phantom对象。如上面代码中,通过phantom对象控制程序终结。示例中其他代码的含义以及更多深入的用法,将在下文中展开。 在使用phantom时,我首先关注的是DOM和BOM接口。不过这不是一个问题,看了下面的代码就能了解: 运行: 结果为 true。也就是说,就像浏览器环境一样,我们的代码运行在window环境下,可以很方便地进行DOM方面的操作。 注:如果使用web page模块打开页面,则请不要在此window对象下进行任何DOM相关的操作,因为这个window并不是page对象内的window。如果想要执行dom相关操作,请参阅page.evaluate()部分。 之前的例子中我们已经初步认识了phantom对象。它的功能是定义和控制phantom运行环境的参数和流程。关键的API有: web page模块的功能是处理具体的页面。使用时需要引入模块,并创建实例: 本文中不经说明, page指代 require("webpage").create()的实例。 联想一下 $.ajax(),可以更好理解这个API。对于这些参数,需要单独阐述的是 callback。callback()会在页面载入完成后调用,由 page.onLoadFinished调用(时机晚于page.onLoadFinished)。这个 callback会接受一个参数 status,可能值为"success"和 "fail",指示页面是否加载成功。示例可以参考“简单示例”一节的例子。 这个方法是同步的,如果执行的内容对后续操作不具备前置性,可以尝试异步方法以提高性能:page.evaluateAsync()。 看一个示例: 第二个参数是 networkRequest实例,它包含3个方法: 可参考如下示例: 通过Child Process模块,我们能创建子进程,借助 stdin、 stdout、 stderr来实现进程间通信(很C++)。使用子进程能够做很多事情,如打印、发邮件、调用脚本或其他程序(不局限于javascript)。 要使用Child Process模块,我们需要在代码中添加 require("child_process")。 以下内容缺乏文档支持,并未经过充分测试,可能存在一定的理解偏差。这部分功能是极有用的,希望在项目中使用的时候注意测试。 Child Process模块本身应该也并完全开发完全。 spawn()、 execFile()可用, exec()和fork()尚未实现。 虽然与node.js中文件系统模块名称和调用方法( require("fs"))一样,但不得不说,phantom的文件系统模块总体是比较简单的,API不多但够用,API也不同于node.js的异步回调风格,而是采用stream+同步的风格,浓浓的C++风味。在使用的时间请一定要注意与node.js的文件系统模块做区分。 在文档一开始就已经提到过system模块,一开始的例子中,我们使用了system模块提供的 args属性。现在重新来认识一下system模块。system模块主要管理着一些与运行环境有关的属性。 phantomjs支持一个简单的web server模块, require(‘webserver‘)即可引入。web server模块基于mongoose。不过最好不要在生产环境使用这样的服务器模块,因为现阶段此模块仅允许10个并发请求。 看一个简单的例子吧: 首先需要创建服务器实例,然后调用 listen()方法监听, listen()方法的第一个参数可以为一个端口号,也可以中 ip:port这样的ip+port组合方式。第二个参数是处理请求的回调方法。下面描述一下 request和 response两个对象。 参考:https://www.cnblogs.com/Sonet-life/p/5393730.html phantomjs api文档 标签:系统路径 标记 requested 可靠 ctr 垃圾回收机制 其他 转化 pass 原文地址:https://www.cnblogs.com/feng-gamer/p/9900707.html安装
使用说明
简单示例
// test.js
var page = require(‘webpage‘).create(),
system = require(‘system‘),
address;
if (system.args.length === 1) {
phantom.exit(1);
} else {
address = system.args[1];
page.open(address, function (status) {
console.log(page.content);
phantom.exit();
});
}
运行:
phantomjs ./test.js http://baidu.com
window对象
// test.js
console.log(window === this);
phantom.exit();
phantomjs ./test.js
phantom对象
获取传给本JS程序的参数,需要与 system.args进行区分(system模块详见下文),后者表示传给phantomjs引擎的参数。例如 phantomjs ./test.js http://baidu.com这句语句,通过phantom.args,我们能得到的参数列表为 ["http://baidu.com"],而通过 system.args则得到 ["./test.js", "http://baidu.com"]这样的参数列表。差异就在于是否包含当前脚本名称。不过 phantom.scriptName这个API提供了获取脚本名称的功能。
获取或设置cookies,不过对于设置建议使用其他的API完成。同时相关的API还有:
把指定的外部JS文件注入到当前环境。执行这个方法时,phantomjs首先会从当前目录检索此文件,如果找不到,则再到 phantom.libraryPath指定的路径寻找。 phantom.libraryPath这个API基本上就是为 phantom.injectJs()服务的。
当页面存在js错误,且没有被 page.onError处理,则会被此handler捕获。下面是使用此API的一个例子。由于phantom环境下代码调试很困难,了解这些错误捕获的API也许会对我们的实际使用有所帮助。
phantom.onError = function(msg, trace) {
var msgStack = [‘PHANTOM ERROR: ‘ + msg];
if (trace && trace.length) {
msgStack.push(‘TRACE:‘);
trace.forEach(function(t) {
msgStack.push(‘ -> ‘ + (t.file || t.sourceURL) + ‘: ‘ + t.line + (t.function ? ‘ (in function ‘ + t.function +‘)‘ : ‘‘));
});
}
console.error(msgStack.join(‘\n‘));
phantom.exit(1);
};
这个API已经见过多次了,它的作用是退出程序,可以设置一个退出代码,默认是0。web page 模块
var webPage = require(‘webpage‘);
var page = webPage.create();
与上文中的 phantom.cookies类似,表示本url下的cookie的读取。同样类似的API还有addCookie()、 deleteCookie()、 clearCookies()。
对于当前页面的一些配置项。此API必须在 page.open()调用之前设置,否则不会起作用。以下是配置项:
* javascriptEnabled 默认 true:是否执行页面内的javascript
phantom允许在请求时在http请求头部添加额外信息,此设置项对这个page里面所有的请求都生效(包含页面和其他资源的请求)。添加的信息并没有限制,但如果设置 User-Agent的值,那么这个值会覆盖掉 page.settings里的设置值。示例:
page.customHeaders = {
"X-Test": "foo",
"DNT": "1"
};
page.libraryPath String
设置是否允许离开当前页面,默认是允许。
此方法用于打开一个网页,是一个很重要的API,它有三种调用形式:
与 page.open()对应,调用 page.close()之后,会释放page所占用的内存,我们不可以在此之后再调用page实例。在实际的操作中,调用此方法并不会完成清空所占内存;javascript的垃圾回收机制也不会回收page实例。但在实际使用中,常常会遇到将一个page实例反复open的情况。在一个页面用完后,记得一定要执行 page.close(),这样在下一次open的时候,才不会重复分配堆栈空间。
对于page打开的页面,往往需要与其进行一些交互。 page.evaluate()提供了在page打开页面的上下文(下文直接用page上下文指代)执行function的功能(类比Chrome开发者工具的控制台)。如下例:
page.open(‘http://m.bing.com‘, function(status) {
var title = page.evaluate(function(s) {
return document.querySelector(s).innerText;
}, ‘title‘);
console.log(title);
phantom.exit();
});
在这个例子中, page.evaluate()接受两个参数,第一个是必需的,表示需要在page上下文运行的函数 fn;第二个是可选的,表示需要传给 fn的参数 param。 fn允许有一个返回值return,并且此返回值最终作为 page.evaluate()的返回值。这边对于刚刚命名的 param和return有一些额外的说明和注意事项。对于整个phantom进程而言, page.evaluate()是跑在一个沙盒中, fn无法访问一切phantom域中的变量;同样 page.evaluate()方法外部也不应该尝试访问page上下文中的内容。那么如果两个作用域需要交换一些数据,只能依靠 param和 return。不过限制很大, param和 return必须为能够转化为JSON字符串,换言之,只能是基本数据类型或者简单对象,像DOM 节点、$对象、function、闭包等就无能为力了。
page.render()能够把当前页面渲染成图片并输出到指定文件中。输出的文件格式由传入的文件扩展名决定,目前支持 PNG、 JPEG、 GIF、 PDF。
var page = require(‘webpage‘).create();
page.open(‘http://github.com/‘, function() {
page.render(‘github.png‘);
phantom.exit();
});
还有其他一些API会对 page.render()产生影响,如:
page.clipRect = {
top: 14,
left: 3,
width: 400,
height: 300
};
还有一些页面设置参数,如果纸张大小,侧边距等,在此不详述。web page也支持输出图片base64格式的字符串,API为 page.renderBase64(),也不再详述。
为了交互的需要(测试的需要),phantom允许通过代码模拟一些交互事件(注意与DOM事件的区分)。
API: sendEvent(mouseEventType[, mouseX, mouseY, button=‘left‘])
mouseEventtype可能的取值为: ‘mouseup‘、 ‘mousedown‘、 ‘mousemove‘、‘doubleclick‘和 ‘click‘,这个参数为必须的。
后两个参数为鼠标事件的坐标位置。最后一个参数为鼠标按键,只对需要按键的事件有效,默认为 ‘left‘,可能值为 ‘right‘、 ‘left‘、 ‘middle‘。
API: sendEvent(keyboardEventType, keyOrKeys, [null, null, modifier])
keyboardEventType可能的取值为 ‘keyup‘、 ‘keydown‘、 ‘keypress‘,第2个参数传入一个键值或一个字符串。键值可以通过 page.event.key来查询调用。第三和第四个参数无效,第五个参数表示同时按下的修饰键。取值情况如下:
page.sendEvent(‘keypress‘, page.event.key.A, null, null, 0x02000000 | 0x08000000);
默认page对应的是frame,如果一个页面中还有其他frame,则可以通过此方法切换page对应的frame。其他类似的方法还有 switchToChildFrame()、 switchToParentFrame()、switchToFocusedFrame()、 switchToMainFrame()等,不再赘述。
页面中常常会有上传文件的操作,但phantom没有界面,因而也就没有办法选择文件上传,通过此方法可以模拟文件上传操作。示例如下:
page.uploadFile(‘input[name=image]‘,‘/path/to/some/photo.jpg‘);
varwebPage=require(‘webpage‘);
varpage=webPage.create();
page.onAlert=function(msg){
console.log(‘ALERT: ‘+msg);
};
page.onPrompt=function(msg,defaultVal){
if(msg==="What‘s your name?"){
return‘PhantomJS‘;
}
// 返回值就是prompt得到的值
returndefaultVal;
};
page.onConfirm=function(msg){
console.log(‘CONFIRM: ‘+msg);
// 返回true相当于点击“确定”,返回false相当于点击“取消”
returntrue;
};
page.onConsoleMessage=function(msg,lineNum,sourceId){
console.log(‘CONSOLE: ‘+msg+‘ (from line #‘+lineNum+‘ in "‘+sourceId+‘")‘);
};
page.onNavigationRequested=function(url,type,willNavigate,main){
console.log(‘Trying to navigate to: ‘+url);
console.log(‘Caused by: ‘+type);
console.log(‘Will actually navigate: ‘+willNavigate);
console.log(‘Sent from the page\‘s main frame: ‘+main);
}
page.onResourceError=function(resourceError){
console.log(‘Unable to load resource (#‘+resourceError.id+‘URL:‘+resourceError.url+‘)‘);
console.log(‘Error code: ‘+resourceError.errorCode+‘. Description: ‘+resourceError.errorString);
};
Child Process模块
最基本的创建进程的方法。前两个参数比较重要,例如现在想从phantom进程中运行一段nodejs脚本,脚本路径为 “main.js”,这个脚本接受一个参数,假定为 “helloworld”,那么如果想得到这段脚本的运行结果应该怎么做呢?参考下面的脚本:
var spawn = require("child_process").spawn;
child = spawn(‘node‘, [‘main.js‘, ‘helloworld‘]);
child.stdout.on("data", function (data) {
console.log("spawnSTDOUT:", JSON.stringify(data))
});
child.stderr.on("data", function (data) {
console.log("spawnSTDERR:", JSON.stringify(data))
});
child.on("exit", function (code) {
console.log("spawnEXIT:", code)
});
setTimeout(function () {
phantom.exit(0)
}, 2000);
其实 spawn()方法没什么神秘的,它就是运行第一个参数表示的命令,第二个参数就是这个命令的参数列表。所以如果要开启一个新的phantom进程,第一个参数为 phantom就行。同样的道理,指定好程序的路径或者是脚本语言解释器的路径,通过这个方法可以做的事情很多。
比较不方便的是,进程间的通信只能通过 stdin、 stdout、 stderr来完成,调用spawn()方法后,还需要对这些交互信息进行监听,上面的例子中演示了监听 stdout和stderr的方法。
就像刚刚说的, spawn()方法稍微感觉有点麻烦,使用 execFile()能够稍稍简化上面的代码。 execFile()的前三个参数与 spawn()的三个参数完全一样,不同的是它多了一个 cb回调函数,看一个例子就知道这个回调函数有什么用了:
var execFile = require("child_process").execFile;
child = execFile(‘node‘, [‘main.js‘, ‘helloworld‘], null,
function (err, stdout, stderr) {
console.log("execFileSTDOUT:", JSON.stringify(stdout))
console.log("execFileSTDERR:", JSON.stringify(stderr))
});
setTimeout(function () {
phantom.exit(0)
}, 2000);
在 execFile()中,对 stdout、 stderr的监听做了封装,简化了我们的代码,不过功能上与 spawn()并无区别。file system模块
open()方法接受两个参数,第一个参数是要打开的文件路径,第二个参数后面还会见到,这里统一说明。如果是字符串,则代表文件打开的模式,可选的有 ‘r‘、 ‘w‘、 ‘a/+‘、‘b‘(read时仅支持 ‘b‘);如果是一个对象,则表示配置项,一共有两个配置项,分别是mode和 charset, mode就是刚刚提到的打开模式, charset表示文件的编码类型。参阅下面的示例:
var fs = require("fs");
var file = fs.open("main.js", ‘r‘);
console.log(file.read());
file.close();
file = fs.open("main.js", ‘a‘);
file.write("123");
file.close();
setTimeout(function () {
phantom.exit(0)
}, 2000);
对打开的文件,我们可以进行读写操作(具体使用与打开模式有关)。如果对一个文件执行了open,请别忘了在文件使用完成后,再对其执行close。
fs.read()方法对文件读取做了封装,不必关心文件的打开关闭,返回值为文件内容。
fs.write()方法对文件写入做了封装,不必关心文件的打开关闭。
System模块
获取运行phantomjs时传入的所有参数,这个不再赘述。
获取当前的环境信息。包含操作系统信息、环境变量信息等等。通过下面的代码来查看一下吧:
var system = require(‘system‘);
var env = system.env;
Object.keys(env).forEach(function (key) {
console.log(key + ‘=‘ + env[key]);
});
setTimeout(function () {
phantom.exit(0)
}, 2000);
获取操作系统信息,返回一个简单对象,这个对象有3个属性: architecture:架构,如“32bit”; name:操作系统名称; version:操作系统版本。
获取当前进程的pid。
永远返回 ‘phantomjs‘Web Server模块
var webserver = require(‘webserver‘);
var server = webserver.create();
var service = server.listen(8080, function(request, response) {
response.statusCode = 200;
response.write(‘<html><body>Hello!</body></html>‘)
response.close();
});