本文概述
PhantomJS是一款无头WebKit, 可使用JavaScript API多平台编写脚本, 可在以下主要操作系统上使用:Windows, Mac OS X, Linux和其他Unices。它具有对各种Web标准的快速本机支持:DOM处理, CSS选择器, JSON, Canvas和SVG。 PhantomJS在后台完全渲染页面, 因此结果可以导出为图像。这非常容易设置, 对于大多数需要生成许多浏览器屏幕截图的项目来说, 这是一种有用的方法(如果你正在寻找仅创建屏幕截图的方式, 我们建议你改为阅读此文章)。
在本文中, 你将学习如何通过模块轻松地将PhantomJS与Node.js结合使用, 或者自己使用Javascript对其进行操作。
要求
你将需要可从PATH访问的PhantomJS(已安装或独立发行版)(在此处了解如何向Windows中的PATH添加变量)。如果路径中没有该文件, 可以稍后在配置中为PhantomJS指定可执行文件。
你可以从官方网站的下载区域的每个平台(Windows, Linux, MacOS等)的以下列表中获取PhantomJS。
注意
在大多数平台上没有安装过程, 因为你将获得带有两个文件夹, examples和bin(包含PhantomJS的可执行文件)的.zip文件。
当你知道PhantomJS在你的计算机中可用时, 就让我们开始吧!
A.使用模块
如果要在Node.js中使用模块与PhantomJS一起使用, 则可以使用@ amir20编写的phantom模块。该模块提供了Node.js中PhantomJS的集成。尽管使用Javascript的工作流程与你用来指导PhantomJS的Javascript不同, 但它仍然易于理解。
要将模块安装在项目中, 请在终端中执行以下命令:
npm install phantom --save
模块安装完成后, 你将可以使用require(” phantom”)访问模块。
工作流程(创建页面, 然后与页面一起执行其他操作)与使用PhantomJS中的纯Javascript编写脚本相似。用createPage方法返回的页面对象是将所有方法发送到幻像的代理。大多数方法调用应与PhantomJS API相同。你必须记住, 每个方法都返回一个Promise。
以下脚本将打开Stack Overflow网站, 并在控制台中打印主页的html:
var phantom = require("phantom");
var _ph, _page, _outObj;
phantom.create().then(function(ph){
_ph = ph;
return _ph.createPage();
}).then(function(page){
_page = page;
return _page.open('https://stackoverflow.com/');
}).then(function(status){
console.log(status);
return _page.property('content')
}).then(function(content){
console.log(content);
_page.close();
_ph.exit();
}).catch(function(e){
console.log(e);
});
如果你使用的是Node.js v7 +, 则可以使用此版本提供的async和await功能。
const phantom = require('phantom');
(async function() {
const instance = await phantom.create();
const page = await instance.createPage();
await page.on("onResourceRequested", function(requestData) {
console.info('Requesting', requestData.url)
});
const status = await page.open('https://stackoverflow.com/');
console.log(status);
const content = await page.property('content');
console.log(content);
await instance.exit();
}());
它大大简化了代码, 并且比Promises易于理解。
B.自己执行
如你可能(应该)知道的那样, 你通过带有一些指令的js文件使用PhantomJS, 然后执行脚本, 将脚本的路径作为命令行中的第一个参数提供(phantomjs /path.to/script-to-execute .js)。要了解如何使用Node.js与PhantomJS进行交互, 请创建以下与PhantomJS完美配合的测试脚本(phantom-script.js)。如果要测试它, 请在终端中使用命令phantomjs phantom-script.js:
/**
* phantom-script.js
*/
"use strict";
// Example using HTTP POST operation in PhantomJS
// This website exists and is for test purposes, dont post sensitive information
var page = require('webpage').create(), server = 'http://posttestserver.com/post.php?dump', data = 'universe=expanding&answer=42';
page.open(server, 'post', data, function (status) {
if (status !== 'success') {
console.log('Unable to post!');
} else {
console.log(page.content);
}
phantom.exit();
});
前面的代码应该只创建一个对网站的POST请求(测试时请检查你是否可以访问Internet)。
现在, 我们将使用Node.js强制转换子进程, 此Node脚本应执行以下命令(与命令行中使用的命令相同):
phantomjs phantom-script.js
为此, 我们将需要child_process模块(默认情况下在Node.js中可用), 并将spawn属性保存在变量中。 child_process.spawn()方法使用给定命令(作为第一个参数)以及args中的命令行参数(作为第二个参数)生成一个新进程。如果省略, 则args默认为空数组。
声明一个变量子代, 该子代具有从使用的生成方法返回的值作为值。在这种情况下, spawn的第一个参数应该是phantomjs可执行文件的路径(如果在路径中, 则只能是phantomjs), 第二个参数应该是一个包含单个元素的数组, 即phantom应该使用的脚本的路径。在子变量中, 为stdout(标准输出)和stderr(标准错误输出)添加一个数据侦听器。这些侦听器的回调将收到一个Uint8Array, 除非将其转换为字符串, 否则你显然无法读取。要将Uint8Array转换为其字符串表示形式, 我们将使用Uint8ArrToString方法(包含在下面的脚本中)。这是一种非常简单的方法, 如果你需要项目中的可伸缩性, 我们建议你在此处阅读更多有关如何将这种数组转换为字符串的方法。
使用以下代码创建一个新脚本(executing-phantom.js):
/**
* executing-phantom.js
*/
var spawn = require('child_process').spawn;
var args = ["./phantom-script.js"];
// In case you want to customize the process, modify the options object
var options = {};
// If phantom is in the path use 'phantomjs', otherwise provide the path to the phantom phantomExecutable
// e.g for windows:
// var phantomExecutable = 'E:\\Programs\\PhantomJS\\bin\\phantomjs.exe';
var phantomExecutable = 'phantomjs';
/**
* This method converts a Uint8Array to its string representation
*/
function Uint8ArrToString(myUint8Arr){
return String.fromCharCode.apply(null, myUint8Arr);
};
var child = spawn(phantomExecutable, args, options);
// Receive output of the child process
child.stdout.on('data', function(data) {
var textData = Uint8ArrToString(data);
console.log(textData);
});
// Receive error output of the child process
child.stderr.on('data', function(err) {
var textErr = Uint8ArrToString(err);
console.log(textErr);
});
// Triggered when the process closes
child.on('close', function(code) {
console.log('Process closed with status code: ' + code);
});
最后一步, 使用以下命令执行上一个节点脚本:
node executing-phantom.js
在控制台中, 你应该获得以下输出:
<html><head></head><body>Time: Thu, 09 Feb 17 06:24:55 -0800
Source ip: xx.xxx.xxx.xxx
Headers (Some may be inserted by server)
REQUEST_URI = /post.php?dump
QUERY_STRING = dump
REQUEST_METHOD = POST
GATEWAY_INTERFACE = CGI/1.1
REMOTE_PORT = 57200
REMOTE_ADDR = 93.210.203.47
HTTP_HOST = posttestserver.com
HTTP_ACCEPT_LANGUAGE = de-DE, en, *
HTTP_ACCEPT_ENCODING = gzip, deflate
HTTP_CONNECTION = close
CONTENT_TYPE = application/x-www-form-urlencoded
CONTENT_LENGTH = 28
HTTP_ORIGIN = null
HTTP_USER_AGENT = Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/538.1 (KHTML, like Gecko) PhantomJS/2.1.1 Safari/538.1
HTTP_ACCEPT = text/html, application/xhtml+xml, application/xml;q=0.9, */*;q=0.8
UNIQUE_ID = WJx7t0BaMGUAAHxjI0EAAAAD
REQUEST_TIME_FLOAT = 1486650295.8916
REQUEST_TIME = 1486650295
Post Params:
key: 'universe' value: 'expanding'
key: 'answer' value: '42'
Empty post body.
Upload contains PUT data:
universe=expanding&answer=42</body></html>
我们个人更喜欢使用自行实现的方法来与PhantomJS一起使用, 因为该模块的学习曲线非常陡峭(至少对于那些知道如何直接与脚本一起使用PhantomJS的人而言), 除了文档不是很好。
编码愉快!
评论前必须登录!
注册