2015-04-26

PhantomJS 介绍

目录

PhantomJS 是什么

PhantomJS 能做什么

安装

hello world

自动投票示例介绍

PhantomJS 是什么

简单的来说 PhantomJS 就是一个无界面的 webkit. 官方介绍如下

PhantomJS is a headless WebKit scriptable with a JavaScript API. It has fast and native support for various web standards: DOM handling, CSS selector, JSON, Canvas, and SVG.

此货再配合 phantomjs-node 就可以无缝的使用 nodejs 的功能. 可谓异常强大.

PhantomJS 能做什么

我在这里列举一些:

  • web 页面截图
  • web 页面保存成 pdf
  • 抓取 web 页面内容
  • 可以使用 JQuery 等前端框架无缝操作 web 页面
  • 可以使用 JS 模拟人工操作 web 页面,比如进行网络投票(通过代理更换 IP)
  • 可以进行 web 页面测试

安装

PhantomJS 的安装也是极其简单, 几乎没有依赖, 如果批量部署可以使用 rpm 实现. 具体见官网教程

hello world

创建一个 hello.js 的文件, 输入如下内容, 然后使用 phantom hello.js 即可输出 Hello, world!

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

自动投票示例介绍

官网有很多例子 大家可以自己看, 下面我分享一个我自己用过的例子.

背景

比如 wenjuan.com 的这个投票, 人家是专门做投票的, 你想要破解他们的防作弊系统, 使用程序投票可能需要花费一些精力了, 但其实你可以使用更简单的方式使用, 那就是使用 PhantomJS 模拟浏览器的行为, 他们是分辨不出来的. 如果想要使用程序自动投票, 那么下面这段代码即可实现.

代码

vote("http://www.wenjuan.com/s/I7fYNv?test=1", ['少明 工商学院 14级', '号 潘露 公管学院 12级 控球', '10号 李秉阳 外国语学院 14级 小前锋'], [''], 0);

// 这是一段 wenjuan.com 网站自动投票代码
/**
 * url      : 字符串 map, 指定 url 和简称
 * must     : 一个字符串数组, 指定投票时必选选择的投票项关键字
 * random   : 一个字符串数组, 指定一组关键字从中随机选择几个进行投票
 * randomNum: 整形, 指定从 random 中随机选择多项进行投票. 之所以这么做是因为 wenjuan.com 投票时对选中的项有限制, 所以需要从一些非必要选项中随机选择投票
 * 使用例子: vote("http://www.wenjuan.com/s/I7fYNv?test=1", ['少明 工商学院 14级', '号 潘露 公管学院 12级 控球', '10号 李秉阳 外国语学院 14级 小前锋'], [''], 0);
**/

function vote(url, must, random, randomNum){
    // 确定投票随机关键字数组
    var arr = []
    for (i=0; i<randomNum; i++){
        // 随机选择一个
        randomIndex = Math.floor(Math.random()*random.length);
        arr.push(random[randomIndex]);
        random.splice(randomIndex, 1);
    }

    // 拼接数组, 现在所有这些都是必选项
    arr = arr.concat(must);

    // 创建 page 对象
    var page = require('webpage').create();

    // 捕获内部的 console 信息
    // page.onConsoleMessage = function(msg) {
    //     console.log('page.evaluate logs ' + msg);
    // };

    // console.log('开始对', url, '进行投票');
    // 投票
    page.open(url, function() {
        d = page.evaluate(function(arr){
            tmpArr = []
            els = $("div.icheckbox_div")
            // 选择复选框
            for(index=0; index<els.length; index++){
                el = els[index];
                checkbox = $(el).find(".jqTransformCheckboxWrapper a:first-child");
                text     = $(el).find("label").text();
                for(kw in arr){
                    // 如果匹配就选择
                    if (text.search(arr[kw]) >=0){
                        $(checkbox).click();
                        tmpArr.push(text);
                        // console.log("key:", arr[kw], text);
                    }
                }
            }
            // 提交
            // $('#next_button').click();
            return tmpArr;
        }, arr);
        page.render('example.png');
        jsonObj = {url: url, items: d}
        console.log(JSON.stringify(jsonObj));
        setTimeout(function(){
           phantom.exit();
        }, 2000);
        // phantom.exit();
    });
}

代码片段分析:

  • page.open 打开投票 url
  • page.evaluate 在投票 web 页面的中执行 javascript 脚本, 相当于在 Chrome 的 console 中执行 javascript 脚本
  • 通过编写 在 page.evaluate 中执行的脚本即可模拟人工填写表单的方式从而进行投票
  • setTimeout(function(){phantom.exit();}, 2000); 投票页面提交以后 wenjuang.com 还要 get 一个页面进行二次确认, 所以需要等两秒再结束进程
  • 更多 PhantomJS 可以参见官方 api 文档

上述代码仅仅是实现了模拟浏览器投票的功能, 但是正常在投票的时候同一个 IP 只能进行一次投票, 如果想要多次投票就需要使用多个 IP 地址, 如果你有很多 vps 的话(可以考虑购买阿里云的 ecs 或者亚马逊的云主机, 购买一小时即可够用) 可以使用ssh 隧道做 socks 代理从而实现更换 ip 的功能

批量购买 vps 例举

  • 阿里云主机最低配置 单核 512M 内存 一小时 0.2元, 详情见官方主页 相当于 2 角钱买一票, 非常便宜
  • 亚马逊 EC2 最低配置 0.015 美元一小时折合人民币不到一角, 比阿里云 ecs 更便宜, 但是其 IP 都是国外的, 对于一些投票项目可能不适用.

使用方法

  • 使用 sh -Nn -D 8080 username@vpn-host 命令打开 socks 隧道
  • 使用 phantom –proxy=127.0.0.1:1080 –proxy-type=socks5 vote.js 通过 socks 代理启动脚本执行投票
  • 如果你还想做的更完美的话可以考虑自己设置一个 ua 集合, 然后每次投票的时候随机选择一个 ua 防止投票系统通过 ua 来查票.

下载 YouTube 视频