腾讯云技术社区-掘金主页持续为大家呈现云计算技术文章,欢迎大家关注!


作者:link

概述

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.(http://phantomjs.org/)

PhantomJS是一个无界面的webkit内核浏览器,你可以把它当作一个没有界面的Safari。

安装

目前PhantomJS的最新版本的2.0,官方文档中有提到说:如果在使用老版本时碰到一些难解的bug,可以升级到最新版试试。

windows

直接下载phantomjs-2.0.0-windows.zip,并解压,将bin文件夹中的可执行文件phantomjs.exe的路径添加到环境变量后(可能需要重启机器才能生效),就可以在命令行环境(cmd或cygwin)中使用phantomjs命令执行js文件了。

Linux

安装二进制文件包

可以在Bitbucket下载已经编译好的二进制文件安装包,不过目前Linux提供到PhantomJS 1.9.8的安装包,最新的PhantomJS 2.0还没有发布。
安装方式:

  1. 下载phantomjs-1.9.8-linux-x86_64.tar.bz2
  2. 进入安装目录,解压二进制文件
> cd /usr/local
> tar zxvf phantomjs-1.9.8-linux-x86_64.tar.bz2
  1. 创建软链接mysql指向解压出来的文件夹,或将解压出来的文件夹重命名为phantomjs:
> ln -sf phantomjs-1.9.8-linux-x86_64/bin/phantomjs phantomjs

编译源码的方式

由于WebKit模块中有数千个文件,因此由源码编译PhantomJS会花费很长的时间,文档上说,开四个并行的进程进行编译工作,需要超过30分钟的时间,因此官方文档推荐直接下载和安装二进制文件。
具体的安装方法,这里就不再赘述,大家可以到官方文档上查看。

是否安装成功

我们可以使用下面的命令来查看PhantomJS是否安装成功:

> phantomjs -v

命令运行phantomjs xxx.js即可执行一个PhantomJS程序。

webpage模块

webpage是PhantomJS的核心模块,你可以通过以下方式,获得一个webpage模块的实例:

var webPage = require("webpage"),page = webPage.create();

open()

打开一个url链接,并加载对应的页面,一旦页面加载完成,就会触发回调,你也可以使用page.onLoadFinished方法来监听页面是否加载完成。下面,我们来用open()方法打开腾讯课堂:

var page = require("webpage").create;page.open("http://ke.qq.com", function(status) { if(status !== "success") { console.log("open fail!"); } phantom.exit(); });

上面的代码中,open()方法接受了两个参数。第一个参数是要打开网页的url(要记得加协议头哦!),默认使用GET方法打开,第二个参数是回调参数,网页加载完成后该函数将会执行,它的参数status表示网页是否打开成功,打开成功就是success,否则就是fail。要注意的是,只要收到服务器返回的结果,status参数就是success,即使服务器返回的是404或500错误。
我们也可以使用其他的http方法打开页面。

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

上面的代码是官方文档的事例,使用POST方法向服务器发送数据。open方法的第二个参数用来指定HTTP方法,第三个参数用来指定该方法所要使用的数据。
从PhantomJS 1.9开始,我们还可以使用json对象来对http请求进行更详细的配置。

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

evaluate()

在打开一个网页后,我们往往有对其进行操作的需求,例如模拟点击登陆按钮、获取某个DOM元素等等,也就是需要在页面中执行javascript代码,这时候我们就需要使用到evaluate()方法。

// 获取打开页面的title
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(); });

由于因为evaluate()方法相当于一个沙盒,在其中是无法访问evaluate()之外的变量的。那如何将我想要获取的dom元素的id传进evaluate呢?
从PhantomJS 1.6开始,我们可以将外部变量以如下的方式传给evaluate内部,需要注意的是,能传入evaluate方法内部的参数只能是简单的基本类型,例如数值、字符串、json对象等能被JSON序列化的类型,而无法接受更复杂的对象,它的返回值也同样如此。

page.open('https://item.taobao.com/item.htm?id=520115087331', function(status) {var domId = "J_SellCounter" var sellCounter = page.evaluate(function(id) { return document.getElementById(id).innerText; }, domId); console.log(sellCounter); phantom.exit(); });

由于open()方法打开的网页内部的console语句,和evaluate()方法中的console语句都不会执行,给我们开发调试带来了不便。这时可以采用onConsoleMessage回调函数,来打印出上面两种情况中的console语句中的信息:

var webPage = require('webpage');
var page = webPage.create();page.onConsoleMessage = function(msg, lineNum, sourceId) { console.log('CONSOLE: ' + msg + ' (from line #' + lineNum + ' in "' + sourceId + '")'); };

其中msg是需要打印的信息,lineNum和sourceId是console.log在文件中的行号以及这个文件对应的标识id。

includeJs()

可以使用includeJs()方法加载外部脚本,例如jquery。

var webPage = require('webpage');
var page = webPage.create();page.open('http://www.example.com', function(status) { if(status !== "success") { console.log("open fail!"); } page.includeJs('http://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'); $('#loginBtn').click(); }); phantom.exit(); }); })

注意,由于includeJs是异步加载脚本,所以phantom.exit()需要放在page.includeJs()的回调函数中,否则phantomjs进程会过早退出。

render()

render()可以将打开的网页截图并保存成本地图片,可以将指定的图片文件名作为参数传入,render方法可以根据文件名的后缀将图片保存成对应的格式。目前支持PNGGIFJPEGPDF四种图片格式。

var webPage = require('webpage');
var page = webPage.create();page.viewportSize = { width: 1920, height: 1080 }; page.open("http://www.google.com", function start(status) { page.render('google_home.jpeg', {format: 'jpeg', quality: '100'}); phantom.exit(); });

该方法的第一个参数是保存的文件名,第二个可选参数是一个JSON对象,format指定图片格式,quality指定0-100区间内的图片质量,必须是整数。

onResourceRequested

当页面去请求一个资源时,会触发onResourceRequested()方法的回调函数。回调函数接受两个参数,第一个参数requestData是这个HTTP请求的元数据对象,包括以下属性:

  • id: 所请求资源的id号,这个应该是phantomjs给标识的。
  • method: 所使用的HTTP方法(GET/POST/PUT/DELETE等)。
  • url: 所请求资源的URL
  • time: 包含请求该资源时间的一个Date对象。
  • headers: 该请求的http请求头中的信息数组。

第二个参数networkRequest包含以下方法:

  • abort(): 终止当前的网络请求,这会导致调用onResourceError回调函数。
  • changeUrl(newUrl):改变当前网络请求的URL。
  • setHeader(key, value):设置HTTP头信息。
var webPage = require('webpage');
var page = webPage.create();page.onResourceRequested = function(requestData, networkRequest) { console.log('Request (#' + requestData.id + '): ' + JSON.stringify(requestData)); }; page.open("http://ke.qq.com", function(status) { if(status) { console.log("fail!"); } phantom.exit(); });

onResourceReceived

onResourceReceived属性用于指定一个回调函数,当网页收到所请求的资源时,就会执行该回调函数。回调函数只有一个参数,就是所请求资源的服务器发来的HTTP response的元数据对象,包括以下字段。

  • id:所请求的资源编号,此编号phantomjs标识。
  • url:所请求的资源的URL
  • time:包含HTTP回应时间的Date对象
  • headers:响应的HTTP头信息数组
  • bodySize:解压缩后的收到的内容大小
  • contentType:接到的内容种类
  • redirectURL:重定向URL(如果有的话)
  • stage:对于多数据块的HTTP回应,头一个数据块为start,最后一个数据块为end。
  • status:HTTP状态码,成功时为200。
  • statusText:HTTP状态信息,比如OK。

需要注意的是,该方法收到的response对象是没有response.body的具体内容的。

可以利用正则表达式,来筛选出我们想要操作的一些响应资源。比如我想从淘宝教育的课程详情页跳转到购买页(在淘宝网中),可以从淘宝同学请求的资源url中筛选出带淘宝网商品详情页的商品id,然后用这个淘宝网商品id拼接成一个淘宝网的商品详情页url,再次使用open()方法打开这个url,就可以跳转到该课程的购买页中。

var page = require('webpage').create(),url1 = "http://i.xue.taobao.com/detail.htm?courseId=32679",url2 = "https://item.taobao.com/item.htm?id=", itemId = 0, mItem = "", siteType = "taobao"; page.onConsoleMessage = function(msg) { console.log('console: ' + msg); }; page.onResourceReceived = function(response) { /*if(mItem = response.url.match(/^http\:\/\/(?:.*)[?|&]item=(\d*)/)) { itemId = mItem[1]; console.log(itemId); phantom.exit(); }*/ // 获取课程对应的淘宝网商品id if(mItem = response.url.match(/itemId=(\d*)/)) { itemId = parseInt(mItem[1]); } } page.open(url1, function(status) { if(status !== "success") { console.log("tongxue fail!"); phantom.exit(); } page.render("tongxue.png"); // 打开课程对应的淘宝商品详情页。 page.open(url2 + itemId, function(status) { if(status !== "success") { console.log("tongxue fail!"); phantom.exit(); } // 由于页面中的资源是动态加载的,需要setTimeout 10s 等待资源加载完,再操作页面。 setTimeout(function() { var apply = page.evaluate(function() { // 获取课程交易量 return document.getElementById("J_SellCounter").innerText; //return document.getElementById("bd").innerHTML; }); console.log("apply:", apply); //fs.write("body.html", apply, "w"); phantom.exit(); }, 10000); }); });

小栗子

动态获取淘宝商品详情页的商品交易量

相信大家都知道爬虫的基本方式无非是抓取页面中的url,然后分析;但是页面中的url也些是静态的,有些事通过js动态生成的,故爬虫也分抓静及抓动之分。
因为淘宝商品详情页的交易量是异步拉取的,在异步数据还没有返回时,页面上交易量那一栏只是一个无意义的“-”,如图:

当异步数据返回后,才会显示出真正的交易量:

因此,

var webPage = require('webpage');
var page = webPage.create();
var pageTb = webPage.create(); var tbUrl = "https://item.taobao.com/item.htm?id=520115087331"; page.settings.userAgent = "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.2454.85 Safari/537.36"; pageTb.open(tbUrl, function(status) { // 由于是拉取异步数据,我们打开页面后,等待12s再去操作dom,获取交易量 setTimeout(function() { var result = pageTb.evaluate(function() { return document.getElementById("J_SellCounter").innerText; }); console.log(result); //生成当前页面截图 pageTb.render("xuqintb2.png"); phantom.exit(); }, 12000); });

win7上执行命令:

$ phantomjs.exe --ssl-protocol=any xuqinTb.js
1379

win7上得到了交易量(由于是打开https协议头的网页,所以执行js文件时,需要添加"--ssl-protocol=any"参数)

PhantomJS不能做什么

  • PhantomJS是一个阉割版的webkit,不支持flash、webGL、video/audio、css 3-d,phontomjs不想背负操作系统强相关的特性,跨平台比较困难。
  • 如果使用Page模块的onResourceReceived()方法监听页面收到的请求资源,是无法得到该资源的response.body的,这也是目前PhantomJS最受开发者吐槽的点之一。

原文链接:http://ivweb.io/topic/560b402ac2317a8c3e08621c

相关推荐

腾讯云上PhantomJS用法示例
腾讯云上Selenium用法示例
包学会之浅入浅出Vue.js:开学篇


此文已由作者授权腾讯云技术社区发布,转载请注明文章出处
原文链接:https://www.qcloud.com/community/article/743451001489391682
获取更多腾讯海量技术实践干货,欢迎大家前往腾讯云技术社区

转载于:https://www.cnblogs.com/libin-1/p/6727282.html

PhantomJS 基础及示例相关推荐

  1. db29.7时间格式化为时间到时分秒_python基础系列 | 示例讲解时间模块datetime

    Python 有很多种方式处理日期和时间,常见的时间处理的模块是datetime.time.calendar.能融汇贯通的了解和使用这三个模块,才能轻而易举地用python处理时间.本文以此为目的,通 ...

  2. 探索MicroPython(三)--基础操作示例

    基础操作示例 1. LED 2. 按键 3. GPIO 4. 外部中断 5. I2C总线 6. ADC 7. DAC 8. UART 1. LED pyBoard中一共有4个LED,分别是是LED(1 ...

  3. 平台全局 css代码,css全局样式基础代码(示例代码)

    简介这篇文章主要介绍了css全局样式基础代码(示例代码)以及相关的经验技巧,文章约900字,浏览量402,点赞数4,值得参考! body{ font-size:12px; font-family:&q ...

  4. (二)01- DCloud平台 HTML5+ App开发——真机调试运行 夜神模拟器运行HBuilderX中的html文件 夜神模拟器运行App的基础功能示例-手机设备-分享功能-拍照功能

    DCloud 平台 HTML5 + App 开发 下载安装 HBuilderX 下载地址:https://www.dcloud.io/hbuilderx.html HBuilderX-使用步骤: 第一 ...

  5. asp.net core系列 59 Ocelot 构建基础项目示例

    一.入门概述 从这篇开始探讨Ocelot,Ocelot是一个.NET API网关,仅适用于.NET Core,用于.NET面向微服务/服务的架构中.当客户端(web站点.ios. app 等)访问we ...

  6. G2O 图优化基础与示例汇总

    在汇总图优化相关知识时,我们知道图优化模型主要是使用g2o进行代码编程.看见<SLAM>P123页时,有4个步骤/ 定义顶点和边的类型: 构建图: 选择优化算法: 调用g2o进行优化,返回 ...

  7. java drools5_Java Drools5.1 规则流基础【示例】

    一.问题描述 假设雇员 Employ 有: 学历信息 eduInfo , 简历信息 resume , 考核信息 annualExam 和奖惩信息  awardPunish : 要确定其: 基本工资 b ...

  8. Confluence 6 配置服务器基础地址示例

    2019独角兽企业重金招聘Python工程师标准>>> 如果 Confluence 的安装是没有安装在非根目录路径(这个是上下文路径),然后服务器基础 URL 地址应该包括上下文地址 ...

  9. C++基础教程示例详解:C++中的I/O重定向

    在C语言中,我们可以使用函数freopen()将现有文件指针重定向到另一个流.freopen()的原型如下 FILE * freopen ( const char * filename, const ...

最新文章

  1. 编程自动化,未来机器人将超越人类?
  2. 部分人说 Java 的性能已经达到甚至超过 C++,是真的吗?
  3. 脑机接口成唯一沟通方式,渐冻症晚期父亲终向4岁儿子表达爱意
  4. python手机版怎么运行项目或脚本-python脚本运行的几种方式
  5. Java xml 工具 JDOM 使用详解.
  6. Python中and、or、not用法
  7. 在html中定位属性怎么用,CSS元素定位的使用方法
  8. 干扰网络信号的app_解决无线网络干扰的五种方法
  9. android 手机主题制作,怎么制作手机主题?
  10. JS导出excel表格
  11. 教师专用录微课及剪辑软件推荐-camtasia及使用教程
  12. iTextSharp 添加图片
  13. 我大学到研究生学过的计算机基础课程(数据结构、计算机网络、算法、操作系统),绝对推荐,全部在这里了!
  14. 说说那些好用的图片调色软件
  15. LeetCode. 15 - 三数之和
  16. 【问题记录】运行python+selenium程序报错,NoSuchWindowException: Browsing context has been discarded
  17. VC++实现会议中阻止屏保、阻止系统自动关闭屏幕、阻止系统待机(附源码)
  18. ftp上传服务器再次下载打开提示文件损坏
  19. mpv播放器键盘快捷键
  20. git@gitlab invalid privatekey

热门文章

  1. 采用TurboGate邮件网关防止企业邮箱被盗用
  2. 15款最好的网站音乐播放器
  3. ORA-01081: cannot start already-running ORACLE - shut it down first
  4. tomcat5配置常见数据库连接池的例子.
  5. aspnet中操作excel报com错误的解决方法
  6. 定位城市_北方城市如何利用GPS定位器减轻铲雪工作压力?
  7. C++实现各种排序算法
  8. Oracle基本操作(二)
  9. Github+Gitlb的使用
  10. 数据挖掘分析的必要性