(1)一个基于webkit内核的无头浏览器,即没有UI界面,即它就是一个浏览器,只是其内的点击、翻页等人为相关操作需要程序设计实现。
(2)提供javascript API接口,即通过编写js程序可以直接与webkit内核交互,在此之上可以结合java语言等,通过java调用js等相关操作,从而解决了以前c/c++才能比较好的基于webkit开发优质采集器的限制。
(3)提供windows、linux、mac等不同os的安装使用包,也就是说可以在不同平台上二次开发采集项目或是自动项目测试等工作。
常用内置几大对象
常用API
注意事项
区分phantomjs的对象和打开的web page的对象,如document、window等,两者都有,在调用page.evaluate和不调用的时候,注意区分二者的范围,容易在调试时出现很多的问题,且不好发现。
page.injectJs和page.includeJs的区别,前者侧重本地的js文件,与libraryPath挂购,后者侧重网络js文件,尤其在引入jquery等第三方库时,会经常遇到。
编码问题,两个重要参数,–output-encoding,–script-encoding,前者为输出编码,后者为所使用js、参数配置文件的编码,为方便起鉴,建议均采用utf-8编码,并注所应用到的目标文件的编码,以免引起很不可思议的异常,又无从查起。
使用总结 : 主要是java se+js+phantomjs的应用,
编写好js脚文程序,预留出所有可配置参数,并提供json文件传输相关参数。
通过java程序,定义相关参数并生成对应的json文件。
通过java命令行调用API,调用phantomjs命令,并传入js、配置文件路径,从而开启爬虫。
首先采集关键词的搜索页的链接集合,最后统一去遍历采集具体的对象网页。
生成的PDF基本还原了其原来的样式,图片和文字分开了,并非直接截图;有生成PDF相关需求的,可以思考生成使用phantomjs 如何实现功能;本人有通过Html模板,生成Html页面,然后将此页面上传至FastDfs服务器,然后通过返回的url直接生成此pdf,即完成了html页面一致的pdf生成功能;
wget https://bitbucket.org/ariya/phantomjs/downloads/phantomjs-2.1.1-linux-x86_64.tar.bz2
yum install bzip2 # 安装bzip2
tar -jxvf phantomjs-2.1.1-linux-x86_64.tar.bz2
mv phantomjs-2.1.1-linux-x86_64 /usr/local/src/phantomjs
ln -sf /usr/local/src/phantomjs/bin/phantomjs /usr/local/bin/phantomjs
yum install fontconfig freetype2
phantomjs -v # 测试版本号
当执行完此命令时,phantomjs已安装成功。可以开始配置环境变量了。
本地电脑
上,并配置好环境变量,可参照章节二教程;WIndows与Linux环境下的区别:①配置好环境变量,因为phantomjs的启动方式,windows是执行exe文件,linux不是,所以配好环境变量后java在本机测试与在Linux下无需做任何修改;② Phantomjs执行生成Echarts图片时,需要引用到 jquery.1.9.1.min.js ,echarts-convert.js, echarts.min.js 以及生成Echarts的js文件。这些js需要引用到,而当部署在Linux中时,生成的js文件在jar包中,不一定能读取到,我们可以通过代码将js文件复制生成到jar包同级目录,然后通过路径加载。路径加载可以用如下代码读取并生成:
~~~java
/* 将模板生成到指定的位置 判断文件是否存在,如果不存在则创建 */
File echartsfile = new File(System.getProperty(“user.dir”) + “\echarts-all.js”);
if (!echartsfile.exists()) {
FileUtil.file2file(“js/echarts-all.js”, System.getProperty(“user.dir”) + “\echarts-all.js”);
}
~~~
public static void main(String[] args) throws Exception {
Runtime rt = Runtime.getRuntime();
//windows 本地地址
Process p = rt.exec("phantomjs " +"C:\\Code\\Demo\\echarts-convert.js" + " -infile " + "C:\\Code\\Demo\\Demo1\\src\\main\\resources\\echarts\\optionsjs\\" + "1187559506027646976.js -outfile " + "C:\\Demo\\" + "123.png -scale 0.01 -width 1200");
InputStream is = p.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(is));
StringBuffer sbf = new StringBuffer();
String tmp = "";
while ((tmp = br.readLine()) != null) {
sbf.append(tmp);
}
System.out.println(sbf);
}
<!-- framework-->
<dependency>
<groupId>org.freemarker</groupId>
<artifactId>freemarker</artifactId>
<version>2.3.26-incubating</version>
</dependency>
// 生成文件
public void createDocNew(Map<String,Object> map,String templatePath,String templateName,String outFilePath) throws Exception{
try (Writer out=new FileWriter(outFilePath)){
//创建一个配置对象,获取该对象的版本
Configuration configuration=new Configuration(Configuration.getVersion());
//获取模板所在目录
configuration.setDirectoryForTemplateLoading(new File(templatePath));
//设置编码集
configuration.setDefaultEncoding("utf-8");
//获取模板对象
Template template=configuration.getTemplate(templateName);
//输出文件至指定目录
template.process(map,out);
//关闭流
} catch (Exception e) {
e.printStackTrace();
}
}
> 这里的代码就是将map里存储的值以及模板地址,和outFilePath的生成地址接收,然后生成出最终的js文件。关于Framework的语法,可以去具体学习,这里不做赘述;当然也可以使用别的方式或者别的模板生成方式;
/* 将模板生成到指定的位置 判断文件是否存在,如果不存在则创建 */
File echartsfile = new File(System.getProperty("user.dir") + "\\echarts-all.js");
if (!echartsfile.exists()) {
FileUtil.file2file("js/echarts-all.js", System.getProperty("user.dir") + "\\echarts-all.js");
}
File jsfile = new File(outPathAndName);
if (!jsfile.exists()) {
FileUtil.string2File(outPathAndName, echartTemplate.getFileContent()); // 将js文件生成到指定的位置
}
File convertfile = new File(System.getProperty("user.dir") + "\\echarts-convert.js");
String echartsPath = System.getProperty("user.dir") + "\\echarts-convert.js";
if (!convertfile.exists()) {
FileUtil.file2file("js/echarts-convert.js", echartsPath);
}
File jqueryfile = new File(System.getProperty("user.dir") + "\\jquery.1.9.1.min.js");
if (!jqueryfile.exists()) {
FileUtil.file2file("js/jquery.1.9.1.min.js", System.getProperty("user.dir") + "\\jquery.1.9.1.min.js");
}
重点代码:System.getProperty(“user.dir”) 为 Windows下或者Linux下的当前路径 ,具体可百度其用法。
public static String parseHtml2Pdf2(String url) throws IOException {
Runtime rt = Runtime.getRuntime();
Process p = rt.exec("C:/App/phantomjs-2.1.1-windows/bin/phantomjs.exe "+ "C:\\Code\\demo\\parsers\\src\\main\\resources\\wordfiles\\js\\jstemplate\\1190147431954702336.js "+url);
InputStream is = p.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(is));
StringBuffer sbf = new StringBuffer();
String tmp = "";
while ((tmp = br.readLine()) != null) {
sbf.append(tmp);
}
String resultstr = sbf.toString();
String[] arr = resultstr.split("\\$");
String result = "";
for(String s : arr){
if(s.endsWith("pdf"))result = s;
}
return result;
}
var page = require('webpage').create();
var system = require('system');
////读取命令行参数,也就是js文件路径。
if (system.args.length === 1) {
console.log('Usage: loadspeed.js ' );
//这行代码很重要。凡是结束必须调用。否则phantomjs不会停止
phantom.exit();
}
page.settings.loadImages = true; //加载图片
page.settings.resourceTimeout = 30000;//超过10秒放弃加载
//截图设置,
//page.viewportSize = {
// width: 1000,
// height: 3000
//};
var address = system.args[1];
page.open(address, function(status) {
function checkReadyState() {//等待加载完成将页面生成pdf
setTimeout(function () {
var readyState = page.evaluate(function () {
return document.readyState;
});
if ("complete" === readyState) {
page.paperSize = { width:'297mm',height:'500mm',orientation: 'portrait',border: '1cm' };
var timestamp = Date.parse(new Date());
var outpathstr = 'C:/Demo/parsers/src/main/resources/wordfiles/pdf_file/1189813692544335872.pdf';
page.render(outpathstr);
//page.render("c://test.png");
//console.log就是传输回去的内容。
console.log("生成成功");
console.log("$"+outpathstr+"$");
phantom.exit();
} else {
checkReadyState();
}
},1000);
}
checkReadyState();
});
这里的 var outpathstr = ‘C:/Demo/parsers/src/main/resources/wordfiles/pdf_file/1189813692544335872.pdf’;需要我们去修改为实际导出的地址,同时要注意在Linux下的路径问题;