PhantomJS简介

  • 时间:2014-06-01
  • 方式:原创

PhantomJS

1.PhantomJS是什么?

PhantomJS is a headless WebKit scriptable with a JavaScript API.

PhantomJS是一个可编程的无头浏览器.

无头浏览器:一个完整的浏览器内核,包括js解析引擎,渲染引擎,请求处理等,但是不包括显示和用户交互页面的浏览器。

2.PhantomJS的使用场景

PhantomJS的适用范围就是无头浏览器的适用范围。通常无头浏览器可以用于页面自动化,网页监控,网络爬虫等:

  • 页面自动化测试:希望自动的登陆网站并做一些操作然后检查结果是否正常。
  • 网页监控:希望定期打开页面,检查网站是否能正常加载,加载结果是否符合预期。加载速度如何等。
  • 网络爬虫:获取页面中使用js来下载和渲染信息,或者是获取链接处使用js来跳转后的真实地址。

我们将使用一个较简单的例子来演示phantomJS如何安装,使用。并用一个稍微复杂的例子来演示Phantom如何做到网页自动化。

3.Hello World

这里的hello world就是打开http://www.baidu.com/并且截屏;

第一步先安装PhantomJS

想要使用PhantomJS,我们需要搭建PhantomJS的环境.

我们可以去官网上下载最新的PhantomJS http://phantomjs.org/;

phantomjs下载后可以直接解压使用了

双击phantomjs.exe就可以看到一个控制台。这时已经进入了PhantomJS的世界

运行的效果:

win

第二步 编写我们的截屏程序

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

page.open("http://www.baidu.com", function start(status) {
  page.render('baidu.jpeg');
  phantom.exit();
});

编写这个简单的程序,保存为helloWorld.js,然后我们在控制台内输入

phantomjs.exe helloWorld.js 

就可以看到运行效果:

baidu

第三步 这个程序里我们都做了什么?

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

这一句是告诉Phantomjs 我们需要webpagae模型,第二句是创建具体是使用对象page。目前Phantom提供的模型有:

  • webpage:最重要的模型,包括打开URL,回退,获取正文、标题,发送事件等
  • child_process:子进程,在不影响主进程情况下。可以用来输入输出,执行JS等操作
  • fs:文件系统,用于写本地文件。
  • system:系统,接受参数等
  • webserver:开放一个端口,搭建一个Phantom的服务

接下来

page.open("http://www.baidu.com", function start(status) {...});

这一句实际上是告诉PhantomJS我们要打开的页面是http://www.baidu.com,并在打开完成后调用start函数。这里是回调的写法。在所有的PhantomJS的对象内。函数都是回调的。

 page.render('baidu.jpeg');
 phantom.exit();

render这个函数是表示将当前页面绘制回来,并保持到baidu.jpeg内。 Phantom.exit()就是退出程序。

phantome.exe  helloWorld.js

使用PhantomJS来执行helloWorld.js这个文件。实际上,在我们执行JS的时候,我们可以指定一些参数。比较重要的有:

  • --cookies-file:cookie文件路径。
  • --load-images:是否加载图片
  • --local-to-remote-url-access:是否允许访问远程地址
  • --proxy:代理设置
  • --script-encoding:页面编码
  • --web-security:允许跨站请求
  • --ssl-protocol:ssl请求设置。

第四步 了解更多

在本例中我们只使用了PhantomJS中最简单的函数。你可以在这里找到Phantoms详细的说明文档:http://phantomjs.org/api/;

4.HelloWorld进阶

在我们的上个例子中,我们已经可以打开百度了,那么为何不更近一步呢。假设我们现在需要获取到百度对一个关键词的搜索结果。怎么办?

我们打开baidu的搜索页,可以发现.实际上baidu的搜索结果现在已经变成了动态加载的了;

search

我们当然可以抓包分析下baidu的执行流程,但是如果他修改了。我们的改动成本肯定相对较大。

那么 我们能不能使用PhantomJS来获取到Baidu搜索后的结果呢?

如果使用Phantom,我们只需要在baidu首页的输入框中输入helloworld,然后点击百度一下来实现搜索功能,并且将baidu搜索出的连接地址保持到一个名为url.txt的文件中即可。

程序如下:

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

var fs = require('fs');
//上文介绍的文件系统 输出文件需要
var path = 'url.txt';

//在PhantomJS中 执行JS函数的时候是不能直接使用Phantom的方法的。需要hook住alert方法,再使用alert来输出
page.onAlert = function(msg) {
    fs.write(path, msg, "w");
};

//引入jquery 让我们的操作更方便。
page.injectJs("jquery-1.6.1.min.js");
page.open("http://www.baidu.com", function(status) {

    //当打开成功后。输入检索内容并点击搜索
    //注意这两个按钮的的ID还是需要人为去看一下的
    if ( status === "success" ) {
        page.evaluate(function(text) {
            $("#kw1").val(text);
            $("#su1").click();
        }, "hello world");

    }

});

//我们需要获取资源加载成功的方法并重写
//更多的phantom的方法可以参考官方链接。
page.onResourceReceived = function (res,network) {
    if (res.stage == "end") {
        //我们仍然需要知道baidu搜索后的结束条件
        if (res.url.indexOf("b1.bdstatic.com")>=0) {
            //获取左边的所有标签并打印出text和链接
            page.evaluate(function() {
                var result="";
                $("#content_left a").each(function(){
                    result=result+$(this).text()+"   "+$(this).attr("href")+"\n";
                });
                alert(result);
            });

            page.render('baidu.jpeg');
            phantom.exit();
        }
    }
};

执行这个脚本。我们可以发现本地文件夹下生成了一个url.txt并且生成了一个点击后的图片

result

5.PhantomJS的坑

PhantomJS提供了一系列的API来让我们编程控制。这些API看似可以帮我们实现一些不易实现的功能。如网页自动化,动态爬虫等等。但是真的有这么美好么?

来让我们看下phantomJS到底有哪些坑:

  • 单线程处理
    • Phantom在处理页面的时候,实际上同浏览器不同。他是单线程下载的。所以通常他很慢。也就是说PhantomJS的加载速度并不完全等于用户访问页面的加载速度
  • 坑爹的JS嵌套
    • 在Phantom中。API本身提供的功能相当的有限。这时我们可能需要借助JS来实现一些功能。但是在JS中又不能饮用Phantom的函数。调用起来会很不方便
  • 用于爬虫处理并没有想象中那么完美
    • PhantomJS的一个重要的功能就是获取JS执行后的内容。但是真的所有的都可以获取到么?其实不然,如下
      • a标签是触发s函数来实现跳转的。js的实现是使用window.location.href="xxx".我们会发现 对于这种写法,我们是没有办法获取到请求地址的。
      • a(按钮)标签点击后修改了当前页面。我们会发现也没有办法直接一次性得到所有的链接

6.PhantomJS总结

虽然PhantomJS并没有那么的完美,但是他也提供了一套自动化页面及ajax爬虫的方案。

根据以往的经验,不建议完全使用PhantomJS来进行开发。而是使用Phantom来实现一些其他语言不方便实现的功能,然后再其他语言来调用。调用方式可以使用services或者是本地命令