返回介绍

9.3 PhantomJS

发布于 2024-01-26 22:39:51 字数 12096 浏览 0 评论 0 收藏 0

9.2节讲了直接从JavaScript中采集加载的数据的方法,本节进行讲解第二种方法,即直接从浏览器中提取渲染好的HTML文档。如果Ajax请求很多,有时请求参数还进行了加密,我们手动分析每一个Ajax请求,将成为一项繁重的工作,而且没有一定的JavaScript分析功底,很难做到。这个时候第二种方法的好处就体现出来了,直接提取浏览器渲染好的结果,不进行Ajax请求分析,PhantomJS就是这样的一个浏览器。

PhantomJS是一个基于WebKit的服务器端JavaScript API。它全面支持Web而无需浏览器支持,不仅运行快,原生支持各种Web标准:DOM处理、CSS选择器、JSON、Canvas,和SVG。PhantomJS可以用于页面自动化、网络监测、网页截屏,以及无界面测试等。PhantomJS可以看做一个没有界面的浏览器,它既有Firefox浏览器、google浏览器的功能,又因为没有界面而更加快速,占更小的内存,在爬虫开发中非常受欢迎。

9.3.1 安装PhantomJS

PhantomJS安装方法有两种,一种是下载源码之后自行编译,另一种是直接下载编译好的二进制文件,官方推荐直接使用编译好的二进制文件。安装下载地址为:http://phantomjs.org/download.html ,包括Windows、Mac OS、Linux版本,自行选择对应版本下载解压即可,建议为PhantomJS设置环境变量。在下载的安装包中,其中有一个example文件夹,里面有很多官方的例子可供学习和参考。

安装完成后在命令行中输入:phantomjs-v。如果正常显示版本号,则证明安装配置成功。图9-5为Windows下的显示结果。

图9-5 phantomJS版本

9.3.2 快速入门

配置完成PhantomJS,下面使用它输出“hello world”。新建一个JavaScript文件hello.js,代码内容为:

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

这时候在命令行中输入:

  phantomjs hello.js

输出内容为:Hello,world!。代码中的第一句是在控制台输出“Hello,world!”,第二句是终止phantom的运行,不然程序会一直运行,不会停止。

通过上面的小例子我们已经了解了PhantomJS的基本操作,PhantomJS还有一些有趣而且强大功能。

1.页面加载

通过PhantomJS,一个网页可以被加载、分析和通过创建网页对象呈现。下面演示一个简单的页面加载的例子,访问我的博客园地址:http://www.cnblogs.com/qiyeboy/ ,并将当前页面进行截图保存。pageload.js代码如下:

  var page = require('webpage').create();
  page.open('http://www.cnblogs.com/qiyeboy/', function(status) {
     console.log("Status: " + status);
     if(status === "success") {
       page.render('qiye.png');
     }
     phantom.exit();
  });

在命令行中运行:

  phantomjs pageload.js

输出内容为:Status:success,并在当前目录下生成对网页的截图qiye.png,如图9-6所示。

图9-6 qiye.png

代码解释:首先使用webpage模块创建一个page对象,然后通过page对象打开http://www.cnblogs.com/qiyeboy/ 网址,如果请求响应状态为success,则通过render方法将当前页面保存为qiye.png图片。

除了打开网页截图之外,还可以对网页的打开进行测速。下面的例子用来计算一个网页的加载速度,同时还用到了给JavaScript脚本传递参数的功能。loadspeed.js代码如下:

  var page = require('webpage').create(),
     system = require('system'),
     t, address;
  
  if (system.args.length === 1) {
     console.log('Usage: loadspeed.js <some URL>');
     phantom.exit();
  }
  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('Loading ' + system.args[1]);
       console.log('Loading time ' + t + ' msec');
     }
     phantom.exit();
  });

在命令行中输入:

  phantomjs loadspeed.js http://www.cnblogs.com/qiyeboy/

输出结果为:

  Loading http://www.cnblogs.com/qiyeboy/
  Loading time 793 msec

代码解释:首先使用webpage模块创建一个page对象,使用system模块获取系统对象system,并声明了两个变量t和address,用来保存时间和传入参数。如果传入参数的长度等于1,说明要加载的地址没有传入,进行提示并退出phantom。为什么要等于1呢?因为phantomjs loadspeed.js第一个参数是loadspeed.js。接着获取当前的时间,然后打开网页,获取加载完成后的时间,进行相减即可。

2.代码评估

为了评估网页中的JavaScript代码,可以利用evaluate。这个执行是“沙盒式”的,它不会去执行网页外的JavaScript代码。evaluate方法可以返回一个对象,然而返回值仅限于对象,不能包含函数(或闭包)。比如我们可以使用evaluate方法获取http://www.cnblogs.com/qiyeboy/ 页面的标题,evaluate.js代码如下:

  var url = 'http://www.cnblogs.com/qiyeboy/';
  var page = require('webpage').create();
  page.open(url, function(status) {
     var title = page.evaluate(function() {
       return document.title;
     });
     console.log('Page title is ' + title);
     phantom.exit();
  });

在命令行中输入:

  phantomjs evaluate.js

输出结果为:

  Page title is七夜的故事 - 博客园

任何来自于网页并且包括来自evaluate()内部代码的控制台信息,默认不会显示。要覆盖此行为,使用onConsoleMessage回调方法。将evaluate.js代码改动如下:

  var url = 'http://www.cnblogs.com/qiyeboy/';
  var page = require('webpage').create();
  page.onConsoleMessage = function(msg) {
     console.log('Page title is ' + msg);
  };
  page.open(url, function(status) {
     page.evaluate(function() {
       console.log(document.title);
     });
     phantom.exit();
  });

在命令行中输入:

  phantomjs evaluate.js

输出结果为:

  Page title is七夜的故事 - 博客园

9.3.3 屏幕捕获

上节简单讲解了如何将网页保存为一张图片,下面详细解释一下这个屏幕捕获的功能。由于PhantomJS使用的是WebKit内核,一个真正的布局和渲染引擎,它可以捕捉一个网页的屏幕截图。另外PhantomJS可以渲染网页上的元素,所以它不仅可以用于HTML和CSS的内容转换,还可以用于SVG和画布。PhantomJS不仅可以将网页保存为png格式,还可以保存为jpg、gif和pdf格式。下面将pageload.js代码进行改动,转成pdf格式,代码如下:

  var page = require('webpage').create();
  page.open('http://www.cnblogs.com/qiyeboy/', function(status) {
     console.log("Status: " + status);
     if(status === "success") {
       page.render('qiye.pdf');
     }
     phantom.exit();
  });

最后生成的pdf文件,效果如图9-7所示。

图9-7 qiye.pdf

PhantomJS不仅可以将页面转化为不同的文件格式,还可以对视图进行缩放和裁剪,主要用到page对象中两个非常重要的属性:viewportSize和clipRect。viewportSize是视区的大小,其作用可以看做是将打开的浏览器窗口进行缩放。clipRect是在这个视区中裁剪矩形的大小,需要四个参数,前两个是基准点,后两个参数是宽高。下面将pageload.js进行改动,代码如下:

  var page = require('webpage').create();
  
  page.viewportSize = { width: 1024, height: 768 };
  page.clipRect = { top: 0, left: 0, width: 512, height: 256 };
  
  page.open('http://www.cnblogs.com/qiyeboy/', function(status) {
     console.log("Status: " + status);
     if(status === "success") {
       page.render('qiye.png');
     }
     phantom.exit();
  });

效果如图9-8所示,只是截取出了顶端一角。

图9-8 网页裁剪

9.3.4 网络监控

因为PhantomJS允许检验网络流量,因此它适合分析网络行为和性能,实现对网络的监听。当向远程服务器发送请求时,可以使用onResourceRequested和onResourceReceived两个方法嗅探所有的资源请求和响应。示例netmonitor.js代码如下:

  var url = 'http://www.cnblogs.com/qiyeboy/';
  var page = require('webpage').create();
  page.onResourceRequested = function(request) {
     console.log('Request ' + JSON.stringify(request, undefined, 4));
  };
  page.onResourceReceived = function(response) {
     console.log('Receive ' + JSON.stringify(response, undefined, 4));
  };
  page.open(url);

在命令行中输入:

  phantomjs netmonitor.js

请求和响应的信息会以JSON的格式进行显示,效果如图9-9所示。

图9-9 网络监控

9.3.5 页面自动化

PhantomJS可以加载和处理一个网页,非常适用于自动化处理,PhantomJS中标准JavaScript的DOM操作和CSS选择器都是生效的。下面使用一个小例子讲解一下DOM操作,获取MTime时光网的影评信息,HTML标记位置如图9-10所示。

图9-10 评分和票房标记

示例代码如下:

  var page = require('webpage').create();
  console.log('The default user agent is ' + page.settings.userAgent);
page.settings.userAgent = 'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:49.0) Gecko/20100101 Firefox/49.0';
  page.open('http://movie.mtime.com/108737/', function(status) {
     if (status !== 'success') {
       console.log('Unable to access network');
     } else {
       var ua = page.evaluate(function() {
            return document.getElementById('ratingRegion').textContent;
       });
       console.log(ua);
     }
     phantom.exit();
  });

输出结果如下:

  The default user agent is Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/ 538.1(KHTML, like Gecko) PhantomJS/2.1.1 Safari/538.1
  7.7总分:104,335人评分 4,299人想看音乐 画面 导演 故事 …票房:5.92亿元

代码解释:首先创建page对象,接着将默认的User-Agent进行了修改,打开指定网页,当加载完成之后,执行DOM操作,获取id为ratingRegion元素下的内容,并打印出来。

大家可以看一下默认UserAgent的内容,会发现里面包含了PhantomJS关键字,一些网站就是通过这个关键字来识别是否正在使用PhantomJS爬取数据。

在1.6版本之后PhantomJS允许添加外部的JS库,比如下面的例子添加了jQuery,然后执行了jQuery代码。

  var page = require('webpage').create();
  page.open('http://www.sample.com', function() {
     page.includeJs("http://ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.min
     .js", function() {
       page.evaluate(function() {
            $("button").click();
       });
       phantom.exit()
     });
  });

9.3.6 常用模块和方法

上面的例子中我们用到了phantom、webpage和system模块,在这三个模块基础上再讲一个fs模块。

1.phantom

对于phantom,主要讲解其中的五个方法,如表9-2所示。

表9-2 phantom方法

2.webpage

对于webpage,主要说一下includeJs、open两个普通方法,onInitialized、onLoadFinished两个回调方法。

includeJs方法原型为includeJs(url,callback){void},功能是包含从指定的URL获取远程javaScript脚本,并执行回调方法。示例代码如下:

  var webPage = require('webpage');
  var page = webPage.create();
  page.includeJs(
     //  Include the https version, you can change this to http if you like.
     'https:// ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js',
     function() {
       (page.evaluate(function() {
            //  jQuery is loaded, now manipulate the DOM
            var $loginForm = $('form# login');
            $loginForm.find('input[name="username"]').value('phantomjs');
            $loginForm.find('input[name="password"]').value('c45p3r');
       }))
     }
  );

open方法比较复杂,有四种函数重载方式,分别为open(url,callback){void}、open(url,method,callback){void}、open(url,method,data,callback){void}、open(url,settings,callback){void}。open(url,callback)方法之前已经用过,第二种和第三种方式类似,所以下面主要说一下后两种形式。

open(url,method,data,callback)中url为链接,method为GET或者POST请求,data为附加的数据,callback为回调函数。示例如下,用于发送一个POST请求。

  var webPage = require('webpage');
  var page = webPage.create();
  var postBody = 'user=username&password=password';
  page.open('http://www.google.com/', 'POST', postBody, function(status) {
     console.log('Status: ' + status);
     //  Do other things here...
  });

open(url,settings,callback)中url为链接,setting为对请求头和内容的设置,callback为回调函数。示例如下:

  var webPage = require('webpage');
  var page = webPage.create();
  var settings = {
     operation: "POST",
     encoding: "utf8",
     headers: {
       "Content-Type": "application/json"
     },
     data: JSON.stringify({
       some: "data",
       another: ["custom", "data"]
     })
  };
  
  page.open('http://your.custom.api', settings, function(status) {
     console.log('Status: ' + status);
     //  Do other things here...
  });

onInitialized是回调方法,在webpage对象被创建之后,url被加载之前被调用,主要是用来操作一些全局变量。示例代码如下:

  var webPage = require('webpage');
  var page = webPage.create();
  page.onInitialized = function() {
     page.evaluate(function() {
       document.addEventListener('DOMContentLoaded', function() {
            console.log('DOM content has loaded.');
       }, false);
     });
  };

onLoadFinished是回调方法,在页面加载完成之后调用,方法还有一个参数status。如果加载成功status为success,否则为fail。webpage中open方法就是用这个方法作为回调函数。示例代码如下:

  var webPage = require('webpage');
  var page = webPage.create();
  
  page.onLoadFinished = function(status) {
     console.log('Status: ' + status);
     //  Do other things here...
  };

3.system

system模块只有属性,没有方法。下面通过表9-3列举一下system的属性及其含义。

表9-3 system属性

4.fs

fs模块全称为File System,主要是对文件系统进行操作。该模块方法很多,这里主要讲解创建文件、判断文件是否存在、读写文件的方法,如表9-4所示。

表9-4 fs方法

以上介绍了一些常用模块和方法,如果大家想详细了解相关内容,可以去phantom官网(http://phantomjs.org/api/ )查看完整的API文档。

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文