phantomjs初见以及官方demo尝试

  • windows配置环境变量
  • 官方demo尝试
    • 向控制台输出内容
    • 获得当前phantomjs的版本信息(涉及到了字符串拼接)
    • 打印系统环境变量(涉及到了for循环)
    • 计时器(js的常用方法)
    • 向js脚本文件传递参数
    • 调用模块
    • 编码输出(设置编码)
    • 发起http-post请求(表单提交)
    • post提交json(设置http请求头)
    • 设置用户代理UA
    • 保存到文件
    • 输出输出
    • 引入jq,获取页面内容
    • 回调
    • 目录扫描
    • 初始化修改全局对象
    • 获取http请求以及响应信息
    • 不加载css读取url
    • 排序
    • 使用代理打开URL
    • 使用HTTP-POST
    • 作为webserver启动(wtf这么屌?)
    • 简单的web服务器
    • 服务端稍微升级
    • 调色盘
    • 探测器
    • 点阵化
    • 多url渲染
    • 等待
    • 运行页面qunit
    • frame层操作?
    • 打印页面header和footer
    • 获取响应式的屏幕快照
    • 获取页面事件

下载地址:http://phantomjs.org/download.html

windows配置环境变量

解压缩到c盘根目录,配置环境变量;然后使用phantomjs命令启动,后面加上js脚本执行。

官方demo尝试

phantomjs的js脚本在执行到最后的时候必须添加函数phantomjs.exit()
如果没有该函数的话,则无法停止,除非通过ctrl+c的方式退出。

向控制台输出内容

hello.js脚本如下

console.log('Hello, world!');
phantom.exit();

执行phantomjs hello.js

可以看到控制台输出了内容。

获得当前phantomjs的版本信息(涉及到了字符串拼接)

version.js脚本如下

console.log('using PhantomJS version ' +
  phantom.version.major + '.' +
  phantom.version.minor + '.' +
  phantom.version.patch);
phantom.exit();

打印系统环境变量(涉及到了for循环)

printenv.js脚本如下

var system = require('system'),
    env = system.env,
    key;

for (key in env) {
    if (env.hasOwnProperty(key)) {
        console.log(key + '=' + env[key]);
    }
}
phantom.exit();

计时器(js的常用方法)

countdown.js代码如下

var t = 10,
    interval = setInterval(function(){
        if ( t > 0 ) {
            console.log(t--);
        } else {
            console.log("BLAST OFF!");
            phantom.exit();
        }
    }, 1000);

向js脚本文件传递参数

arguments.js代码如下

var system = require('system');
if (system.args.length === 1) {
    console.log('Try to pass some args when invoking this script!');
} else {
    system.args.forEach(function (arg, i) {
            console.log(i + ': ' + arg);
    });
}
phantom.exit();

获取的参数是一个数组,第一个固定的是js文件的名称,然后从第二个开始是我们传入的参数。

对应的下标是从0开始的。

调用模块

universe.js模块内容如下

exports.answer = 42;

exports.start = function () {
    console.log('Starting the universe....');
}

模块无法单独运行

module.js调用模块代码如下

var universe = require('./universe');
universe.start();
console.log('The answer is ' + universe.answer);
phantom.exit();

输出结果是
Starting the universe….
The answer is 42

编码输出(设置编码)

outputEncoding.js代码如下

function helloWorld() {
 console.log(phantom.outputEncoding + ": こんにちは、世界!");
}

console.log("Using default encoding...");
helloWorld();

console.log("\nUsing other encodings...");

var encodings = ["euc-jp", "sjis", "utf8", "System"];
for (var i = 0; i < encodings.length; i++) {
    phantom.outputEncoding = encodings[i];
    helloWorld();
}

phantom.exit()

输出的结果是
Using default encoding…
UTF-8: 銇撱倱銇仭銇€佷笘鐣岋紒

Using other encodings…
EUC-JP: こんにちは、坤肠—
Shift_JIS: 偙傫偵偪偼丄悽奅両
UTF-8: 銇撱倱銇仭銇€佷笘鐣岋紒
UTF-8: 銇撱倱銇仭銇€佷笘鐣岋紒

可以看到我们可以使用phantom.outputEncoding=编码方式
来设置编码

发起http-post请求(表单提交)

post.js代码如下

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();
});

看起来是可以通过page.content的方式获得响应体。

post提交json(设置http请求头)

postjson.js代码如下

var page = require('webpage').create(),
    server = 'http://posttestserver.com/post.php?dump',
    data = '{"universe": "expanding", "answer": 42}';

var headers = {
    "Content-Type": "application/json"
}

page.open(server, 'post', data, headers, function (status) {
    if (status !== 'success') {
        console.log('Unable to post!');
    } else {
        console.log(page.content);
    }
    phantom.exit();
});

设置用户代理UA

useragent.js代码如下

var page = require('webpage').create();
console.log('The default user agent is ' + page.settings.userAgent);
page.settings.userAgent = 'SpecialAgent';
page.open('http://www.httpuseragent.org', function (status) {
    if (status !== 'success') {
        console.log('Unable to access network');
    } else {
        var ua = page.evaluate(function () {
            return document.getElementById('qua').innerText;
        });
        console.log(ua);
    }
    phantom.exit();
});

保存到文件

echoToFile.js代码如下

var fs = require('fs'),
    system = require('system');

if (system.args.length < 3) {
    console.log("Usage: echoToFile.js DESTINATION_FILE ");
    phantom.exit(1);
} else {
    var content = '',
        f = null,
        i;
    for ( i= 2; i < system.args.length; ++i ) {
        content += system.args[i] + (i === system.args.length-1 ? '' : ' ');
    }

    try {
        fs.write(system.args[1], content, 'w');
    } catch(e) {
        console.log(e);
    }

    phantom.exit();
}

使用的时候观察一下,可以看到第一个参数是文件的存储路径,后面的参数都会被存储到文件中。

phantomjs echoToFile.js C:/hello.txt "Hello World"

输出输出

stdin-stdout-stderr.js代码如下

var system = require('system');

system.stdout.write('Hello, system.stdout.write!');
system.stdout.writeLine('\nHello, system.stdout.writeLine!');

system.stderr.write('Hello, system.stderr.write!');
system.stderr.writeLine('\nHello, system.stderr.writeLine!');

system.stdout.writeLine('system.stdin.readLine(): ');
var line = system.stdin.readLine();
system.stdout.writeLine(JSON.stringify(line));

// This is essentially a `readAll`
system.stdout.writeLine('system.stdin.read(5): (ctrl+D to end)');
var input = system.stdin.read(5);
system.stdout.writeLine(JSON.stringify(input));

phantom.exit(0);

输出结果如下

Hello, system.stdout.write!
Hello, system.stdout.writeLine!
Hello, system.stderr.write!
Hello, system.stderr.writeLine!
system.stdin.readLine():

引入jq,获取页面内容

phantomwebintro.js代码如下

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

page.onConsoleMessage = function(msg) {
    console.log(msg);
};

page.open("http://phantomjs.org/", function(status) {
    if (status === "success") {
        page.includeJs("http://ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.min.js", function() {
            page.evaluate(function() {
                console.log("$(\".explanation\").text() -> " + $(".explanation").text());
            });
            phantom.exit(0);
        });
    } else {
      phantom.exit(1);
    }
});

回调

pagecallback.js代码如下

var p = require("webpage").create();

p.onConsoleMessage = function(msg) { console.log(msg); };

// Calls to "callPhantom" within the page 'p' arrive here
p.onCallback = function(msg) {
    console.log("Received by the 'phantom' main context: "+msg);
    return "Hello there, I'm coming to you from the 'phantom' context instead";
};

p.evaluate(function() {
    // Return-value of the "onCallback" handler arrive here
    var callbackResponse = window.callPhantom("Hello, I'm coming to you from the 'page' context");
    console.log("Received by the 'page' context: "+callbackResponse);
});

phantom.exit();

目录扫描

scandir.js代码如下

var system = require('system');

if (system.args.length !== 2) {
    console.log("Usage: phantomjs scandir.js DIRECTORY_TO_SCAN");
    phantom.exit(1);
}

var scanDirectory = function (path) {
    var fs = require('fs');
    if (fs.exists(path) && fs.isFile(path)) {
        console.log(path);
    } else if (fs.isDirectory(path)) {
        fs.list(path).forEach(function (e) {
            if ( e !== "." && e !== ".." ) { //< Avoid loops
                scanDirectory(path + '/' + e);
            }
        });
    }
};
scanDirectory(system.args[1]);
phantom.exit();

扫描整个目录
phantomjs scandir.js c:/

初始化修改全局对象

在页面初始化时修改全局对象。
在这个例子中,有效的math.random()总是返回0.42。

unrandomize.js代码如下

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

page.onInitialized = function () {
    page.evaluate(function () {
        Math.random = function() {
            return 45/100;
        };
    });
};

page.open('http://ariya.github.com/js/random/', function (status) {
    var result;

    if (status !== 'success') {
        console.log('Network error.');
    } else {
        console.log(page.evaluate(function () {
            return document.getElementById('numbers').textContent;
        }));
    }
    phantom.exit();
});

获取http请求以及响应信息

netlog.js代码如下

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

if (system.args.length === 1) {
    console.log('Usage: netlog.js ');
    phantom.exit(1);
} else {
    address = system.args[1];

    page.onResourceRequested = function (req) {
        console.log('requested: ' + JSON.stringify(req, undefined, 4));
    };

    page.onResourceReceived = function (res) {
        console.log('received: ' + JSON.stringify(res, undefined, 4));
    };

    page.open(address, function (status) {
        if (status !== 'success') {
            console.log('FAIL to load the address');
        }
        phantom.exit();
    });
}
···

调用: `phantomjs netlog.js "http://www.baidu.com"`

## 加载速度

loadspeed.js代码如下

```js
var page = require('webpage').create(),
    system = require('system'),
    t, address;


phantom.outputEncoding = "GB2312";       

if (system.args.length === 1) {
    console.log('Usage: loadspeed.js ');
    phantom.exit(1);
} else {
    t = Date.now();
    address = system.args[1];
    page.open(address, function (status) {
        if (status !== 'success') {
            console.log('FAIL to load the address');
        } else {
            t = Date.now() - t;
            console.log('Page title is ' + page.evaluate(function () {
                return document.title;
            }));
            console.log('Loading time ' + t + ' msec');
        }
        phantom.exit();
    });
}




class="se-preview-section-delimiter">div>

调用:phantomjs loadspeed.js "http://www.baidu.com"

不加载css读取url

loadurlwithcss.js代码如下

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

if (system.args.length < 2) {
    console.log('Usage: loadurlwithoutcss.js URL');
    phantom.exit();
}

var address = system.args[1];

page.onResourceRequested = function(requestData, request) {
    if ((/http:\/\/.+?\.css/gi).test(requestData['url']) || requestData.headers['Content-Type'] == 'text/css') {
        console.log('The url of the request is matching. Aborting: ' + requestData['url']);
        request.abort();
    }
};

page.open(address, function(status) {
    if (status === 'success') {
        phantom.exit();
    } else {
        console.log('Unable to load the address!');
        phantom.exit();
    }
});




<div class="se-preview-section-delimiter">div>

排序

sleepsort.js代码如下

var system = require('system');

function sleepSort(array, callback) {
    var sortedCount = 0,
        i, len;
    for ( i = 0, len = array.length; i < len; ++i ) {
        setTimeout((function(j){
            return function() {
                console.log(array[j]);
                ++sortedCount;
                (len === sortedCount) && callback();
            };
        }(i)), array[i]);
    }
}

if ( system.args.length < 2 ) {
    console.log("Usage: phantomjs sleepsort.js PUT YOUR INTEGERS HERE SEPARATED BY SPACES");
    phantom.exit(1);
} else {
    sleepSort(system.args.slice(1), function() {
        phantom.exit();
    });
}




class="se-preview-section-delimiter">div>

调用:phantomjs sleepsort.js 10 30 12

使用代理打开URL

openurlwithproxy.js代码如下
···js
var page = require(‘webpage’).create(),
system = require(‘system’),
host, port, address;

if (system.args.length < 4) {
console.log(‘Usage: openurlwithproxy.js ’);
phantom.exit(1);
} else {
host = system.args[1];
port = system.args[2];
address = system.args[3];
phantom.setProxy(host, port, ‘manual’, ”, ”);
page.open(address, function (status) {
if (status !== ‘success’) {
console.log(‘FAIL to load the address “’ +
address + ‘” using proxy “’ + host + ‘:’ + port + ‘”’);
} else {
console.log(‘Page title is ’ + page.evaluate(function () {
return document.title;
}));
}
phantom.exit();
});
}
···

使用HTTP-POST

postserver.js代码如下

var page = require('webpage').create(),
    server = require('webserver').create(),
    system = require('system'),
    data = 'universe=expanding&answer=42';

if (system.args.length !== 2) {
    console.log('Usage: postserver.js ');
    phantom.exit(1);
}

var port = system.args[1];

service = server.listen(port, function (request, response) {
    console.log('Request received at ' + new Date());

    response.statusCode = 200;
    response.headers = {
        'Cache': 'no-cache',
        'Content-Type': 'text/plain;charset=utf-8'
    };
    response.write(JSON.stringify(request, null, 4));
    response.close();
});

page.open('http://localhost:' + port + '/', 'post', data, function (status) {
    if (status !== 'success') {
        console.log('Unable to post!');
    } else {
        console.log(page.plainText);
    }
    phantom.exit();
});




<div class="se-preview-section-delimiter">div>

作为webserver启动(wtf这么屌?)

var port, server, service,
    system = require('system');

if (system.args.length !== 2) {
    console.log('Usage: serverkeepalive.js ');
    phantom.exit(1);
} else {
    port = system.args[1];
    server = require('webserver').create();

    service = server.listen(port, { keepAlive: true }, function (request, response) {
        console.log('Request at ' + new Date());
        console.log(JSON.stringify(request, null, 4));

        var body = JSON.stringify(request, null, 4);
        response.statusCode = 200;
        response.headers = {
            'Cache': 'no-cache',
            'Content-Type': 'text/plain',
            'Connection': 'Keep-Alive',
            'Keep-Alive': 'timeout=5, max=100',
            'Content-Length': body.length
        };
        response.write(body);
        response.close();
    });

    if (service) {
        console.log('Web server running on port ' + port);
    } else {
        console.log('Error: Could not create web server listening on port ' + port);
        phantom.exit();
    }
}




class="se-preview-section-delimiter">div>

参数是端口号。

简单的web服务器

simpleserver.js代码如下

var port, server, service,
    system = require('system');

if (system.args.length !== 2) {
    console.log('Usage: simpleserver.js ');
    phantom.exit(1);
} else {
    port = system.args[1];
    server = require('webserver').create();

    service = server.listen(port, function (request, response) {

        console.log('Request at ' + new Date());
        console.log(JSON.stringify(request, null, 4));

        response.statusCode = 200;
        response.headers = {
            'Cache': 'no-cache',
            'Content-Type': 'text/html'
        };
        response.write('');
        response.write('');
        response.write('Hello, world!');
        response.write('');
        response.write('');
        response.write('

This is from PhantomJS web server.

'
); response.write('

Request data:

'
); response.write('
');
        response.write(JSON.stringify(request, null, 4));
        response.write('
'
); response.write(''); response.write(''); response.close(); }); if (service) { console.log('Web server running on port ' + port); } else { console.log('Error: Could not create web server listening on port ' + port); phantom.exit(); } }
class="se-preview-section-delimiter">div>

服务端稍微升级

server.js代码如下

var page = require('webpage').create();
var server = require('webserver').create();
var system = require('system');
var host, port;

if (system.args.length !== 2) {
    console.log('Usage: server.js ');
    phantom.exit(1);
} else {
    port = system.args[1];
    var listening = server.listen(port, function (request, response) {
        console.log("GOT HTTP REQUEST");
        console.log(JSON.stringify(request, null, 4));

        // we set the headers here
        response.statusCode = 200;
        response.headers = {"Cache": "no-cache", "Content-Type": "text/html"};
        // this is also possible:
        response.setHeader("foo", "bar");
        // now we write the body
        // note: the headers above will now be sent implictly
        response.write("YES!");
        // note: writeBody can be called multiple times
        response.write("

pretty cool :)"); response.close(); }); if (!listening) { console.log("could not create web server listening on port " + port); phantom.exit(); } var url = "http://localhost:" + port + "/foo/bar.php?asdf=true"; console.log("SENDING REQUEST TO:"); console.log(url); page.open(url, function (status) { if (status !== 'success') { console.log('FAIL to load the address'); } else { console.log("GOT REPLY FROM SERVER:"); console.log(page.content); } phantom.exit(); }); }

class="se-preview-section-delimiter">div>

调色盘

colorwheel.js代码如下

var page = require('webpage').create();
page.viewportSize = { width: 400, height : 400 };
page.content = '';
page.evaluate(function() {
    var el = document.getElementById('surface'),
        context = el.getContext('2d'),
        width = window.innerWidth,
        height = window.innerHeight,
        cx = width / 2,
        cy = height / 2,
        radius = width  / 2.3,
        imageData,
        pixels,
        hue, sat, value,
        i = 0, x, y, rx, ry, d,
        f, g, p, u, v, w, rgb;

    el.width = width;
    el.height = height;
    imageData = context.createImageData(width, height);
    pixels = imageData.data;

    for (y = 0; y < height; y = y + 1) {
        for (x = 0; x < width; x = x + 1, i = i + 4) {
            rx = x - cx;
            ry = y - cy;
            d = rx * rx + ry * ry;
            if (d < radius * radius) {
                hue = 6 * (Math.atan2(ry, rx) + Math.PI) / (2 * Math.PI);
                sat = Math.sqrt(d) / radius;
                g = Math.floor(hue);
                f = hue - g;
                u = 255 * (1 - sat);
                v = 255 * (1 - sat * f);
                w = 255 * (1 - sat * (1 - f));
                pixels[i] = [255, v, u, u, w, 255, 255][g];
                pixels[i + 1] = [w, 255, 255, v, u, u, w][g];
                pixels[i + 2] = [u, u, w, 255, 255, v, u][g];
                pixels[i + 3] = 255;
            }
        }
    }

    context.putImageData(imageData, 0, 0);
    document.body.style.backgroundColor = 'white';
    document.body.style.margin = '0px';
});

page.render('colorwheel.png');

phantom.exit();





<div class="se-preview-section-delimiter">div>

该代码执行完毕后就会在当前目录下生成一个调色板的图片。

探测器

detectsniff.js代码如下

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

page.onInitialized = function () {
    page.evaluate(function () {

        (function () {
            var userAgent = window.navigator.userAgent,
                platform = window.navigator.platform;

            window.navigator = {
                appCodeName: 'Mozilla',
                appName: 'Netscape',
                cookieEnabled: false,
                sniffed: false
            };

            window.navigator.__defineGetter__('userAgent', function () {
                window.navigator.sniffed = true;
                return userAgent;
            });

            window.navigator.__defineGetter__('platform', function () {
                window.navigator.sniffed = true;
                return platform;
            });
        })();
    });
};

if (system.args.length === 1) {
    console.log('Usage: detectsniff.js ');
    phantom.exit(1);
} else {
    address = system.args[1];
    console.log('Checking ' + address + '...');
    page.open(address, function (status) {
        if (status !== 'success') {
            console.log('FAIL to load the address');
            phantom.exit();
        } else {
            window.setTimeout(function () {
                sniffed = page.evaluate(function () {
                    return navigator.sniffed;
                });
                if (sniffed) {
                    console.log('The page tried to sniff the user agent.');
                } else {
                    console.log('The page did not try to sniff the user agent.');
                }
                phantom.exit();
            }, 1500);
        }
    });
}




class="se-preview-section-delimiter">div>

点阵化

rasterize.js代码如下

var page = require('webpage').create(),
    system = require('system'),
    address, output, size;

if (system.args.length < 3 || system.args.length > 5) {
    console.log('Usage: rasterize.js URL filename [paperwidth*paperheight|paperformat] [zoom]');
    console.log('  paper (pdf output) examples: "5in*7.5in", "10cm*20cm", "A4", "Letter"');
    console.log('  image (png/jpg output) examples: "1920px" entire page, window width 1920px');
    console.log('                                   "800px*600px" window, clipped to 800x600');
    phantom.exit(1);
} else {
    address = system.args[1];
    output = system.args[2];
    page.viewportSize = { width: 600, height: 600 };
    if (system.args.length > 3 && system.args[2].substr(-4) === ".pdf") {
        size = system.args[3].split('*');
        page.paperSize = size.length === 2 ? { width: size[0], height: size[1], margin: '0px' }
                                           : { format: system.args[3], orientation: 'portrait', margin: '1cm' };
    } else if (system.args.length > 3 && system.args[3].substr(-2) === "px") {
        size = system.args[3].split('*');
        if (size.length === 2) {
            pageWidth = parseInt(size[0], 10);
            pageHeight = parseInt(size[1], 10);
            page.viewportSize = { width: pageWidth, height: pageHeight };
            page.clipRect = { top: 0, left: 0, width: pageWidth, height: pageHeight };
        } else {
            console.log("size:", system.args[3]);
            pageWidth = parseInt(system.args[3], 10);
            pageHeight = parseInt(pageWidth * 3/4, 10); // it's as good an assumption as any
            console.log ("pageHeight:",pageHeight);
            page.viewportSize = { width: pageWidth, height: pageHeight };
        }
    }
    if (system.args.length > 4) {
        page.zoomFactor = system.args[4];
    }
    page.open(address, function (status) {
        if (status !== 'success') {
            console.log('Unable to load the address!');
            phantom.exit(1);
        } else {
            window.setTimeout(function () {
                page.render(output);
                phantom.exit();
            }, 200);
        }
    });
}




class="se-preview-section-delimiter">div>

可以把页面以pdf或者图片的形式保存到本地,可以说是黑科技了
phantomjs rasterize.js "https://www.bilibili.com/" "c:/bilibili.pdf"

多url渲染

这个就是上面那个的加强版,不需要输入协议名称

render_multi_url.js代码如下

// Render Multiple URLs to file

"use strict";
var RenderUrlsToFile, arrayOfUrls, system;

system = require("system");

/*
Render given urls
@param array of URLs to render
@param callbackPerUrl Function called after finishing each URL, including the last URL
@param callbackFinal Function called after finishing everything
*/
RenderUrlsToFile = function(urls, callbackPerUrl, callbackFinal) {
    var getFilename, next, page, retrieve, urlIndex, webpage;
    urlIndex = 0;
    webpage = require("webpage");
    page = null;
    getFilename = function() {
        return "rendermulti-" + urlIndex + ".png";
    };
    next = function(status, url, file) {
        page.close();
        callbackPerUrl(status, url, file);
        return retrieve();
    };
    retrieve = function() {
        var url;
        if (urls.length > 0) {
            url = urls.shift();
            urlIndex++;
            page = webpage.create();
            page.viewportSize = {
                width: 800,
                height: 600
            };
            page.settings.userAgent = "Phantom.js bot";
            return page.open("http://" + url, function(status) {
                var file;
                file = getFilename();
                if (status === "success") {
                    return window.setTimeout((function() {
                        page.render(file);
                        return next(status, url, file);
                    }), 200);
                } else {
                    return next(status, url, file);
                }
            });
        } else {
            return callbackFinal();
        }
    };
    return retrieve();
};

arrayOfUrls = null;

if (system.args.length > 1) {
    arrayOfUrls = Array.prototype.slice.call(system.args, 1);
} else {
    console.log("Usage: phantomjs render_multi_url.js [domain.name1, domain.name2, ...]");
    arrayOfUrls = ["www.google.com", "www.bbc.co.uk", "phantomjs.org"];
}

RenderUrlsToFile(arrayOfUrls, (function(status, url, file) {
    if (status !== "success") {
        return console.log("Unable to render '" + url + "'");
    } else {
        return console.log("Rendered '" + url + "' at '" + file + "'");
    }
}), function() {
    return phantom.exit();
});




<div class="se-preview-section-delimiter">div>

使用:phantomjs render_multi_url.js "bilibili.com"

可以在当前目录下生成对应抓取网页的图片。

等待

waitfor.js代码如下

/**
 * Wait until the test condition is true or a timeout occurs. Useful for waiting
 * on a server response or for a ui change (fadeIn, etc.) to occur.
 *
 * @param testFx javascript condition that evaluates to a boolean,
 * it can be passed in as a string (e.g.: "1 == 1" or "$('#bar').is(':visible')" or
 * as a callback function.
 * @param onReady what to do when testFx condition is fulfilled,
 * it can be passed in as a string (e.g.: "1 == 1" or "$('#bar').is(':visible')" or
 * as a callback function.
 * @param timeOutMillis the max amount of time to wait. If not specified, 3 sec is used.
 */

"use strict";
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 condition is fulfilled
                    clearInterval(interval); //< Stop this interval
                }
            }
        }, 250); //< repeat check every 250ms
};


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

// Open Twitter on 'sencha' profile and, onPageLoad, do...
page.open("http://twitter.com/#!/sencha", function (status) {
    // Check for page load success
    if (status !== "success") {
        console.log("Unable to access network");
    } else {
        // Wait for 'signin-dropdown' to be visible
        waitFor(function() {
            // Check in the page if a specific element is now visible
            return page.evaluate(function() {
                return $("#signin-dropdown").is(":visible");
            });
        }, function() {
           console.log("The sign-in dialog should be visible now.");
           phantom.exit();
        });
    }
});





<div class="se-preview-section-delimiter">div>

等待时间过长会出现timeout

运行页面qunit

run-qunit.js代码如下

"use strict";
var system = require('system');

/**
 * Wait until the test condition is true or a timeout occurs. Useful for waiting
 * on a server response or for a ui change (fadeIn, etc.) to occur.
 *
 * @param testFx javascript condition that evaluates to a boolean,
 * it can be passed in as a string (e.g.: "1 == 1" or "$('#bar').is(':visible')" or
 * as a callback function.
 * @param onReady what to do when testFx condition is fulfilled,
 * it can be passed in as a string (e.g.: "1 == 1" or "$('#bar').is(':visible')" or
 * as a callback function.
 * @param timeOutMillis the max amount of time to wait. If not specified, 3 sec is used.
 */

  phantom.outputEncoding = "GB2312"
function waitFor(testFx, onReady, timeOutMillis) {
    var maxtimeOutMillis = timeOutMillis ? timeOutMillis : 3001, //< 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 condition is fulfilled
                    clearInterval(interval); //< Stop this interval
                }
            }
        }, 100); //< repeat check every 250ms
};


if (system.args.length !== 2) {
    console.log('Usage: run-qunit.js URL');
    phantom.exit(1);
}

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

// Route "console.log()" calls from within the Page context to the main Phantom context (i.e. current "this")
page.onConsoleMessage = function(msg) {
    console.log(msg);
};

page.open(system.args[1], function(status){
    if (status !== "success") {
        console.log("Unable to access network");
        phantom.exit(1);
    } else {
        waitFor(function(){
            return page.evaluate(function(){
                var el = document.getElementById('qunit-testresult');
                if (el && el.innerText.match('completed')) {
                    return true;
                }
                return false;
            });
        }, function(){
            var failedNum = page.evaluate(function(){
                var el = document.getElementById('qunit-testresult');
                console.log(el.innerText);
                try {
                    return el.getElementsByClassName('failed')[0].innerHTML;
                } catch (e) { }
                return 10000;
            });
            phantom.exit((parseInt(failedNum, 10) > 0) ? 1 : 0);
        });
    }
});





<div class="se-preview-section-delimiter">div>

frame层操作?

还不清楚具体用法

walk_through_frames.js

"use strict";
var p = require("webpage").create();

function pageTitle(page) {
    return page.evaluate(function(){
        return window.document.title;
    });
}

function setPageTitle(page, newTitle) {
    page.evaluate(function(newTitle){
        window.document.title = newTitle;
    }, newTitle);
}

p.open("../test/webpage-spec-frames/index.html", function(status) {
    console.log("pageTitle(): " + pageTitle(p));
    console.log("currentFrameName(): "+p.currentFrameName());
    console.log("childFramesCount(): "+p.childFramesCount());
    console.log("childFramesName(): "+p.childFramesName());
    console.log("setPageTitle(CURRENT TITLE+'-visited')"); setPageTitle(p, pageTitle(p) + "-visited");
    console.log("");

    console.log("p.switchToChildFrame(\"frame1\"): "+p.switchToChildFrame("frame1"));
    console.log("pageTitle(): " + pageTitle(p));
    console.log("currentFrameName(): "+p.currentFrameName());
    console.log("childFramesCount(): "+p.childFramesCount());
    console.log("childFramesName(): "+p.childFramesName());
    console.log("setPageTitle(CURRENT TITLE+'-visited')"); setPageTitle(p, pageTitle(p) + "-visited");
    console.log("");

    console.log("p.switchToChildFrame(\"frame1-2\"): "+p.switchToChildFrame("frame1-2"));
    console.log("pageTitle(): " + pageTitle(p));
    console.log("currentFrameName(): "+p.currentFrameName());
    console.log("childFramesCount(): "+p.childFramesCount());
    console.log("childFramesName(): "+p.childFramesName());
    console.log("setPageTitle(CURRENT TITLE+'-visited')"); setPageTitle(p, pageTitle(p) + "-visited");
    console.log("");

    console.log("p.switchToParentFrame(): "+p.switchToParentFrame());
    console.log("pageTitle(): " + pageTitle(p));
    console.log("currentFrameName(): "+p.currentFrameName());
    console.log("childFramesCount(): "+p.childFramesCount());
    console.log("childFramesName(): "+p.childFramesName());
    console.log("setPageTitle(CURRENT TITLE+'-visited')"); setPageTitle(p, pageTitle(p) + "-visited");
    console.log("");

    console.log("p.switchToChildFrame(0): "+p.switchToChildFrame(0));
    console.log("pageTitle(): " + pageTitle(p));
    console.log("currentFrameName(): "+p.currentFrameName());
    console.log("childFramesCount(): "+p.childFramesCount());
    console.log("childFramesName(): "+p.childFramesName());
    console.log("setPageTitle(CURRENT TITLE+'-visited')"); setPageTitle(p, pageTitle(p) + "-visited");
    console.log("");

    console.log("p.switchToMainFrame()"); p.switchToMainFrame();
    console.log("pageTitle(): " + pageTitle(p));
    console.log("currentFrameName(): "+p.currentFrameName());
    console.log("childFramesCount(): "+p.childFramesCount());
    console.log("childFramesName(): "+p.childFramesName());
    console.log("setPageTitle(CURRENT TITLE+'-visited')"); setPageTitle(p, pageTitle(p) + "-visited");
    console.log("");

    console.log("p.switchToChildFrame(\"frame2\"): "+p.switchToChildFrame("frame2"));
    console.log("pageTitle(): " + pageTitle(p));
    console.log("currentFrameName(): "+p.currentFrameName());
    console.log("childFramesCount(): "+p.childFramesCount());
    console.log("childFramesName(): "+p.childFramesName());
    console.log("setPageTitle(CURRENT TITLE+'-visited')"); setPageTitle(p, pageTitle(p) + "-visited");
    console.log("");

    phantom.exit();
});





<div class="se-preview-section-delimiter">div>

打印页面header和footer

没发现和之前的有不同

printheaderfooter.js代码如下

"use strict";
var page = require('webpage').create(),
    system = require('system');

function someCallback(pageNum, numPages) {
    return "

someCallback: " + pageNum + " / " + numPages + "

"
; } if (system.args.length < 3) { console.log('Usage: printheaderfooter.js URL filename'); phantom.exit(1); } else { var address = system.args[1]; var output = system.args[2]; page.viewportSize = { width: 600, height: 600 }; page.paperSize = { format: 'A4', margin: "1cm", /* default header/footer for pages that don't have custom overwrites (see below) */ header: { height: "1cm", contents: phantom.callback(function(pageNum, numPages) { if (pageNum == 1) { return ""; } return "

Header " + pageNum + " / " + numPages + "

"
; }) }, footer: { height: "1cm", contents: phantom.callback(function(pageNum, numPages) { if (pageNum == numPages) { return ""; } return "

Footer " + pageNum + " / " + numPages + "

"
; }) } }; page.open(address, function (status) { if (status !== 'success') { console.log('Unable to load the address!'); } else { /* check whether the loaded page overwrites the header/footer setting, i.e. whether a PhantomJSPriting object exists. Use that then instead of our defaults above. example:

asdfadsf

asdfadsfycvx

*/
if (page.evaluate(function(){return typeof PhantomJSPrinting == "object";})) { paperSize = page.paperSize; paperSize.header.height = page.evaluate(function() { return PhantomJSPrinting.header.height; }); paperSize.header.contents = phantom.callback(function(pageNum, numPages) { return page.evaluate(function(pageNum, numPages){return PhantomJSPrinting.header.contents(pageNum, numPages);}, pageNum, numPages); }); paperSize.footer.height = page.evaluate(function() { return PhantomJSPrinting.footer.height; }); paperSize.footer.contents = phantom.callback(function(pageNum, numPages) { return page.evaluate(function(pageNum, numPages){return PhantomJSPrinting.footer.contents(pageNum, numPages);}, pageNum, numPages); }); page.paperSize = paperSize; console.log(page.paperSize.header.height); console.log(page.paperSize.footer.height); } window.setTimeout(function () { page.render(output); phantom.exit(); }, 200); } }); }
class="se-preview-section-delimiter">div>

获取响应式的屏幕快照

responsive-screenshot.js

/**
 * Captures the full height document even if it's not showing on the screen or captures with the provided range of screen sizes.
 *
 * A basic example for taking a screen shot using phantomjs which is sampled for https://nodejs-dersleri.github.io/
 *
 * usage : phantomjs responsive-screenshot.js {url} [output format] [doClipping]
 *
 * examples >
 *      phantomjs responsive-screenshot.js https://nodejs-dersleri.github.io/
 *      phantomjs responsive-screenshot.js https://nodejs-dersleri.github.io/ pdf
 *      phantomjs responsive-screenshot.js https://nodejs-dersleri.github.io/ true
 *      phantomjs responsive-screenshot.js https://nodejs-dersleri.github.io/ png true
 *
 * @author Salih sagdilek 
 */

/**
 * http://phantomjs.org/api/system/property/args.html
 *
 * Queries and returns a list of the command-line arguments.
 * The first one is always the script name, which is then followed by the subsequent arguments.
 */
var args = require('system').args;
/**
 * http://phantomjs.org/api/fs/
 *
 * file system api
 */
var fs = require('fs');

/**
 * http://phantomjs.org/api/webpage/
 *
 * Web page api
 */
var page = new WebPage();

/**
 * if url address does not exist, exit phantom
 */
if ( 1 === args.length ) {
    console.log('Url address is required');
    phantom.exit();
}

/**
 *  setup url address (second argument);
 */
var urlAddress = args[1].toLowerCase();


/**
 * set output extension format
 * @type {*}
 */
var ext = getFileExtension();

/**
 * set if clipping ?
 * @type {boolean}
 */
var clipping = getClipping();

/**
 * setup viewports
 */
var viewports = [
    {
        width : 1200,
        height : 800
    },
    {
        width : 1024,
        height : 768
    },
    {
        width : 768,
        height : 1024
    },
    {
        width : 480,
        height : 640
    },
    {
        width : 320,
        height : 480
    }
];

page.open(urlAddress, function (status) {
    if ( 'success' !== status ) {
        console.log('Unable to load the url address!');
    } else {
        var folder = urlToDir(urlAddress);
        var output, key;

        function render(n) {
            if ( !!n ) {
                key = n - 1;
                page.viewportSize = viewports[key];
                if ( clipping ) {
                    page.clipRect = viewports[key];
                }
                output = folder + "/" + getFileName(viewports[key]);
                console.log('Saving ' + output);
                page.render(output);
                render(key);
            }
        }

        render(viewports.length);
    }
    phantom.exit();
});

/**
 * filename generator helper
 * @param viewport
 * @returns {string}
 */
function getFileName(viewport) {
    var d = new Date();
    var date = [
        d.getUTCFullYear(),
        d.getUTCMonth() + 1,
        d.getUTCDate()
    ];
    var time = [
        d.getHours() <= 9 ? '0' + d.getHours() : d.getHours(),
        d.getMinutes() <= 9 ? '0' + d.getMinutes() : d.getMinutes(),
        d.getSeconds() <= 9 ? '0' + d.getSeconds() : d.getSeconds(),
        d.getMilliseconds()
    ];
    var resolution = viewport.width + (clipping ? "x" + viewport.height : '');

    return date.join('-') + '_' + time.join('-') + "_" + resolution + ext;
}

/**
 * output extension format helper
 *
 * @returns {*}
 */
function getFileExtension() {
    if ( 'true' != args[2] && !!args[2] ) {
        return '.' + args[2];
    }
    return '.png';
}

/**
 * check if clipping
 *
 * @returns {boolean}
 */
function getClipping() {
    if ( 'true' == args[3] ) {
        return !!args[3];
    } else if ( 'true' == args[2] ) {
        return !!args[2];
    }
    return false;
}

/**
 * url to directory helper
 *
 * @param url
 * @returns {string}
 */
function urlToDir(url) {
    var dir = url
        .replace(/^(http|https):\/\//, '')
        .replace(/\/$/, '');

    if ( !fs.makeTree(dir) ) {
        console.log('"' + dir + '" is NOT created.');
        phantom.exit();
    }
    return dir;
}





class="se-preview-section-delimiter">div>

获取页面事件

page_events.js

// The purpose of this is to show how and when events fire, considering 5 steps
// happening as follows:
//
//      1. Load URL
//      2. Load same URL, but adding an internal FRAGMENT to it
//      3. Click on an internal Link, that points to another internal FRAGMENT
//      4. Click on an external Link, that will send the page somewhere else
//      5. Close page
//
// Take particular care when going through the output, to understand when
// things happen (and in which order). Particularly, notice what DOESN'T
// happen during step 3.
//
// If invoked with "-v" it will print out the Page Resources as they are
// Requested and Received.
//
// NOTE.1: The "onConsoleMessage/onAlert/onPrompt/onConfirm" events are
// registered but not used here. This is left for you to have fun with.
// NOTE.2: This script is not here to teach you ANY JavaScript. It's aweful!
// NOTE.3: Main audience for this are people new to PhantomJS.

"use strict";

phantom.outputEncoding = "UTF-8";

var sys = require("system"),
    page = require("webpage").create(),
    logResources = false,
    step1url = "http://en.wikipedia.org/wiki/DOM_events",
    step2url = "http://en.wikipedia.org/wiki/DOM_events#Event_flow";

if (sys.args.length > 1 && sys.args[1] === "-v") {
    logResources = true;
}

function printArgs() {
    var i, ilen;
    for (i = 0, ilen = arguments.length; i < ilen; ++i) {
        console.log("    arguments[" + i + "] = " + JSON.stringify(arguments[i]));
    }
    console.log("");
}

////////////////////////////////////////////////////////////////////////////////

page.onInitialized = function() {
    console.log("page.onInitialized");
    printArgs.apply(this, arguments);
};
page.onLoadStarted = function() {
    console.log("page.onLoadStarted");
    printArgs.apply(this, arguments);
};
page.onLoadFinished = function() {
    console.log("page.onLoadFinished");
    printArgs.apply(this, arguments);
};
page.onUrlChanged = function() {
    console.log("page.onUrlChanged");
    printArgs.apply(this, arguments);
};
page.onNavigationRequested = function() {
    console.log("page.onNavigationRequested");
    printArgs.apply(this, arguments);
};
page.onRepaintRequested = function() {
    console.log("page.onRepaintRequested");
    printArgs.apply(this, arguments);
};

if (logResources === true) {
    page.onResourceRequested = function() {
        console.log("page.onResourceRequested");
        printArgs.apply(this, arguments);
    };
    page.onResourceReceived = function() {
        console.log("page.onResourceReceived");
        printArgs.apply(this, arguments);
    };
}

page.onClosing = function() {
    console.log("page.onClosing");
    printArgs.apply(this, arguments);
};

// window.console.log(msg);
page.onConsoleMessage = function() {
    console.log("page.onConsoleMessage");
    printArgs.apply(this, arguments);
};

// window.alert(msg);
page.onAlert = function() {
    console.log("page.onAlert");
    printArgs.apply(this, arguments);
};
// var confirmed = window.confirm(msg);
page.onConfirm = function() {
    console.log("page.onConfirm");
    printArgs.apply(this, arguments);
};
// var user_value = window.prompt(msg, default_value);
page.onPrompt = function() {
    console.log("page.onPrompt");
    printArgs.apply(this, arguments);
};

////////////////////////////////////////////////////////////////////////////////

setTimeout(function() {
    console.log("");
    console.log("### STEP 1: Load '" + step1url + "'");
    page.open(step1url);
}, 0);

setTimeout(function() {
    console.log("");
    console.log("### STEP 2: Load '" + step2url + "' (load same URL plus FRAGMENT)");
    page.open(step2url);
}, 5000);

setTimeout(function() {
    console.log("");
    console.log("### STEP 3: Click on page internal link (aka FRAGMENT)");
    page.evaluate(function() {
        var ev = document.createEvent("MouseEvents");
        ev.initEvent("click", true, true);
        document.querySelector("a[href='#Event_object']").dispatchEvent(ev);
    });
}, 10000);

setTimeout(function() {
    console.log("");
    console.log("### STEP 4: Click on page external link");
    page.evaluate(function() {
        var ev = document.createEvent("MouseEvents");
        ev.initEvent("click", true, true);
        document.querySelector("a[title='JavaScript']").dispatchEvent(ev);
    });
}, 15000);

setTimeout(function() {
    console.log("");
    console.log("### STEP 5: Close page and shutdown (with a delay)");
    page.close();
    setTimeout(function(){
        phantom.exit();
    }, 100);
}, 20000);

你可能感兴趣的:(js)