Phantomjs 进程通信方式
2015-08-20 10:24
721 查看
Phantomjs[1]是一款无界面Webkit浏览器,可用于网页自动化测试。最近一个项目涉及到Phantomjs与其他进程间的通信,以下介绍其他进程中如何调用Phantomjs作数据接口。
目的:其他程序调用Phantomjs,以Java为例
1. 命令行方式
通过命令行可以启动Phantomjs进程,在Java中可以用Runtime.getRuntime.exec(String cmd)的方式。这种方式网上很多例子,这里不详细说。在这种方式下,每次调用Phantomjs都需要启动一个进程,调用完退出,而开启一次Phantomjs进程比较费时,所以这种方式不适合于生产环境。
2. 驱动方式
Selenium提供PhantomjsDriver,提供了在Java直接调用Phantomjs的一系列方法。这种方式下只能调用驱动提供的方法,不能直接调用js文件,不够灵活,因此这次项目中没有用这个方式。有需要可以查阅PhantomjsDriver[2]有关文档。
3. Webserver方式
Phantomjs提供了Webserver[3]模块,可以用该模块来搭建http服务器。通过Webserver监听端口,Java发起Http请求,就可以实现两者通信的目的。
Phantomjs充当服务端,解析一个URL对应网站的title,然后把title返回。
Java充当客户端,根据URL列表查询URL的title信息
把Phantomjs保存为D:/script.js,用Phantomjs加载(phantomjs D:/script.js 9999)。Java发起请求后,Phantomjs接收Request的Post参数作为要查询的URL地址,获取该网站的title后通过Response返回。Java收到Response后,把title打印到console。
在现阶段最新版本中,Webserver模块并未开发得很完善,尤其是在并发方面。所以不建议将这种方式用于大并发的情况下。
4. std方式
进程间最基本的通信方式,相比起Webserver,稳定性更好一些。但同样,不适合用于大并发的情况下。
先看Java端,PhantomjsConnector用于维护Java和Phantomjs之间的std流。
当实例化时,java通过命令行启动Phantomjs进程并保持IO流的连接。执行查询时,向流输出字符(url),然后从流中读取内容(Phantomjs返回的title)。程序完成后可根据pid结束Phantomjs进程。
主类中,只需要循环执行PhantomjsConnector的exec方法。
再看Phantomjs端,在js脚本中首先返回本次进程的pid,然后循环监听std输入的内容。
在只启动一个进程的情况下,Phantomjs只能同时间执行一个查询操作,一次查询结束后才能监听下一个url。在多线程场景下,可以在Java端启动多个Phantomjs的进程,对应多个PhantomjsConnector实例,根据需求把各个类动态分给不同的线程(BlockingQueue可实现),具体不作陈述。
除此以外,Phantomjs与其他语言还有一些集成化驱动,比如与nodejs的phantomjs-node模块之类。以上的只是基本的几种方式,具体选用什么方式通信,还是要根据业务需求决定。
参考资料及引用:
[1] Phantomjs:Phantomjs官网.
http://phantomjs.org/
[2] PhantomjsDriver:Github. GhostDriver.
https://github.com/detro/ghostdriver
[3] Webserver模块:Phantomjs官网. Phantomjs Api.
http://phantomjs.org/api/webserver/
目的:其他程序调用Phantomjs,以Java为例
1. 命令行方式
通过命令行可以启动Phantomjs进程,在Java中可以用Runtime.getRuntime.exec(String cmd)的方式。这种方式网上很多例子,这里不详细说。在这种方式下,每次调用Phantomjs都需要启动一个进程,调用完退出,而开启一次Phantomjs进程比较费时,所以这种方式不适合于生产环境。
2. 驱动方式
Selenium提供PhantomjsDriver,提供了在Java直接调用Phantomjs的一系列方法。这种方式下只能调用驱动提供的方法,不能直接调用js文件,不够灵活,因此这次项目中没有用这个方式。有需要可以查阅PhantomjsDriver[2]有关文档。
3. Webserver方式
Phantomjs提供了Webserver[3]模块,可以用该模块来搭建http服务器。通过Webserver监听端口,Java发起Http请求,就可以实现两者通信的目的。
Phantomjs充当服务端,解析一个URL对应网站的title,然后把title返回。
var webserver = require('webserver').create(); var page = require('webpage').create(); var system = require('system'); var port = system.args[1]; //取第二个参数为端口号 webserver.listen(system.args[1], function(request, response) { var url = request.postRaw; //接收post数据为url page.open(url, function(status) { var title = page.evaluate(function() { return document.title; }); response.write(title); response.close(); }); });
Java充当客户端,根据URL列表查询URL的title信息
public class Demo { public static void main(String[] arg) { //要查询的URL地址列表 String[] urls = new String[]{ "http://www.baidu.com/", "http://www.cnblogs.com/", "http://www.w3school.com.cn/" }; for (int i=0; i<urls.length; i++) { //Http类的详细代码不提供,可用HttpURLConnection或HttpClient封装 Http http = new Http("http://127.0.0.1:9999"); //Phantomjs开放的端口 http.setParam(urls[i]); //设置Post参数(URL地址) http.post(); //发起Post请求 System.out.println(http.getResponse()); } } }
把Phantomjs保存为D:/script.js,用Phantomjs加载(phantomjs D:/script.js 9999)。Java发起请求后,Phantomjs接收Request的Post参数作为要查询的URL地址,获取该网站的title后通过Response返回。Java收到Response后,把title打印到console。
在现阶段最新版本中,Webserver模块并未开发得很完善,尤其是在并发方面。所以不建议将这种方式用于大并发的情况下。
4. std方式
进程间最基本的通信方式,相比起Webserver,稳定性更好一些。但同样,不适合用于大并发的情况下。
先看Java端,PhantomjsConnector用于维护Java和Phantomjs之间的std流。
public class PhantomjsConnector { private String pid; //进程PID private OutputStream out; private PrintWriter writer; private InputStream in; private InputStreamReader inReader; private BufferedReader reader; public PhantomjsConnector() { try { Process process = Runtime.getRuntime().exec("phantomjs D:/script.js"); //通过命令行启动phantomjs //初始化IO流 in = process.getInputStream(); inReader = new InputStreamReader(in, "utf-8"); reader = new BufferedReader(inReader); pid = reader.readLine(); //从phantomjs脚本中获取本进程的PID out = process.getOutputStream(); writer = new PrintWriter(out); } catch (Exception e) { close(); e.printStackTrace(); } } //结束当前维护的进程 public void kill() { try { close(); //先关闭IO流 Runtime.getRuntime().exec("taskkill /F /PID " + pid); //Windows下清除进程的命令,Linux则为kill -9 pid } catch (Exception e) { e.printStackTrace(); } } //执行查询 public String exec(String url) throws IOException { writer.println(url); //把url输出到phantomjs writer.flush(); //立即输出 return reader.readLine(); //读取phantomjs的输出 } //关闭IO private void close() { try { if (in!=null) in.close(); if (inReader!=null) inReader.close(); if (reader!=null) reader.close(); if (out!=null) out.close(); if (writer!=null) writer.close(); } catch (IOException e) { e.printStackTrace(); } } }
当实例化时,java通过命令行启动Phantomjs进程并保持IO流的连接。执行查询时,向流输出字符(url),然后从流中读取内容(Phantomjs返回的title)。程序完成后可根据pid结束Phantomjs进程。
主类中,只需要循环执行PhantomjsConnector的exec方法。
public class Demo { public static void main(String[] arg) throws IOException { //要查询的URL地址列表 String[] urls = new String[]{ "http://www.baidu.com/", "http://www.cnblogs.com/", "http://www.w3school.com.cn/" }; PhantomjsConnector connector = new PhantomjsConnector(); for (int i=0; i<urls.length; i++) { String title = connector.exec(urls[i]); System.out.println(title); } connector.kill(); //最后结束该进程 } }
再看Phantomjs端,在js脚本中首先返回本次进程的pid,然后循环监听std输入的内容。
var system = require("system"); console.log(system.pid); //本次进程pid //监听std输入 var listen = function() { var url = system.stdin.readLine(); //接收std内容为url var page = require('webpage').create(); page.open(url, function(status) { var title = page.evaluate(function() { return document.title; }); system.stdout.writeLine(title); //再通过stdout输出 system.stdout.flush(); //立即输出 //稍作延迟再开始下一次监听 setTimeout(function() { listen(); }, 100); }); }; listen();
在只启动一个进程的情况下,Phantomjs只能同时间执行一个查询操作,一次查询结束后才能监听下一个url。在多线程场景下,可以在Java端启动多个Phantomjs的进程,对应多个PhantomjsConnector实例,根据需求把各个类动态分给不同的线程(BlockingQueue可实现),具体不作陈述。
除此以外,Phantomjs与其他语言还有一些集成化驱动,比如与nodejs的phantomjs-node模块之类。以上的只是基本的几种方式,具体选用什么方式通信,还是要根据业务需求决定。
参考资料及引用:
[1] Phantomjs:Phantomjs官网.
http://phantomjs.org/
[2] PhantomjsDriver:Github. GhostDriver.
https://github.com/detro/ghostdriver
[3] Webserver模块:Phantomjs官网. Phantomjs Api.
http://phantomjs.org/api/webserver/
相关文章推荐
- JS函数式编程【译】4.2 函数组合
- 开启JS学习之路
- JS中将日期字符串转换为日期型过程中出现的问题
- JavaScript 自动分页插件 datatables
- javascript -- 事件捕获,事件冒泡
- 关于placeholder.js在IE78密码文本的提示文字调整
- js代码实现无缝滚动(文字和图片)
- js图片翻书效果代码分享
- JS给Textarea文本框添加行号的方法
- json与jsonp的区别
- js Unicode编码相互转换
- js实现Select列表内容自动滚动效果代码
- js Unicode编码相互转换
- JavaScript中几种=的用法比较
- Post返回json值
- 使用正则表达式的格式化与高亮显示json字符串
- javascript如何操作HTML下拉列表标签
- JS类以面向对象的方式继承
- 七夕情人节丘比特射箭小游戏
- 01.JSP基础语法