编写爬虫时,如果单纯是静态网站,Nodejs的cheerio,requests以及Python的urlib、urlib2与request(BeautifulSoup)就能解决需求。如果碰上网站通过AJAX获取数据或者JS延迟获取数据时。上面的技术栈就比较难获取到我们想要的数据,PhantomJS这个无界面浏览器,又有人称"虚拟浏览器"就派上用场了。
Phantomjs的功能,就是提供一个命令行下使用,它是基于Webkit内核,我们可以使用像正常的浏览器访问所需的网站。在某些时候,很多的人搭配着selenium+phantomjs搭建可以访问动态获取数据的网站,现在先说phantomjs在爬虫中的用法。
- 1.安装phantomjs
- phantomjs是个二进制程序,可以到phantomjs官网下载。如果你安装了nodejs的npm包管理器,也可以直接运行下面命令安装:
npm install phantomjs -g
- 2.如果是直接下载phantomjs二进制文件,还需要把程序文件的路径添加到环境变量的path里。这样方便我们直接在全局调用phantomjs。
- 3.在windows的DOS命令行窗口,直接输入phantomjs直接开启程序,phantomjs为我们提供RPEL环境,可以直接解释javascript。
- 4.在phantomjs提供的REPL环境下输入以下命令,可以实例输出
# >>>表示是输出行
phantomjs --version
>>>2.1.1
phantomjs>window.navigator
{
"appCodeName": "Mozilla",
"appName": "Netscape",
"appVersion": "5.0 (Windows NT 6.1; WOW64) AppleWebKit/538.1 (KHTML, like Gec
ko) PhantomJS/2.1.1 Safari/538.1",
"cookieEnabled": true,
"language": "zh-CN",
"mimeTypes": {
"length": 0
},
"onLine": true,
"platform": "Win32",
"plugins": {
"length": 0
},
"product": "Gecko",
"productSub": "20030107",
"userAgent": "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/538.1 (KHTML, l
ike Gecko) PhantomJS/2.1.1 Safari/538.1",
"vendor": "Apple Computer, Inc.",
"vendorSub": ""
}
- 5.打开sublimetext编写一个js文件,代码如下;并且运用phantomjs运行代码文件。在阮一峰老师phantomjs文档强调,不管怎么样的程序里面,phantom.exit()这行不能少。phantom.exit()表示退出REPL环境:
#代码实例代码
function plus(a,b){
return a*b;
}
console.log(plus(1,2));
phantom.exit()
#以下为命令行窗口运行的情况
>phantomjs spider.js
2
- 6.webpage模块:open()
- webpage模块是phantomjs核心的模块:可以把webpage看做一个类,通过实例化webpage类对象,然后调用对象的方法进行获取网页,最后使用类方法进行操作。
- open(url,callback):open方法默认第一个参数为url地址,callback是回调函数,参数只有Status。无论后台服务器返回的是500或者400状态码,status的状态值都是success的值。
- open()方法默认是以get方法获取数据;open()方法也可以使用其他的方式;例如以post方式,open(url,'post',postData,callback);open方法的第二个参数用来指定HTTP方法,第三个参数用来指定所要传递的参数。
- 下面给出简单的完整的获取百度首页的代码:
# 这是默认get的获取方法
var webPage=require('webpage');
#设置网页的编码格式,如果不设置,会出现乱码情况
phantom.outputEncoding="gbk";
#创建一个webpage实例对象
var page=webPage.create();
var tbUrl="https://www.baidu.com";
#设置浏览器伪headers
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";
# 调用open方法打开具体网页,默认以get请求获取
page.open(tbUrl,function (status) {
setTimeout(function(){
var result=pageTab.evaluate(function(){
return document.body
});
console.log(result.toString());
pageTab.render("1.png");
phantom.exit();
},4000);
})
#post方法传参数获取网页数据
var webPage=require('webpage');
var page=webPage.create();
var postData="username&password"
page.open('http://www.kiwis.com/','post',postData,function(status){
console.log(status);
phantom.exit();
});
# open()方法提供配置对象,对HTTP请求进行详细的配置
var webPage=require('webpage');
var page=webPage.create();
var setting={
operation:"POST",
encoding:"urf8",
headers:{
"Content-Type":"application/json"
},
data:JSON.stringify({
some:'something',
others:['data1']
})
};
page.open("http://www.kiwis.com",setting,function(status){
console.log("Status:"+status);
phantom.exit();
});
- 7.webpage模块:evaluate()方法
- evaluate(callback):evaluate方法可以在数据网页返回之后,可以直接evaluate执行javascript语句进行数据的提取和解析,这也是使用phantomjs作为爬虫提取数据的关键所在。
var webpage=require('webpage');
page=webPage.create();
page.open("https://www.baidu.com",function(status){
var title=page.evaluate(function(){
console.log(document.title);
return document.title;
});
phantom.exit();
});
- 8.webpage模块:onConsoleMessage():在网页内的console语句和evaluate方法内部的console语句,默认不会显示在标准输出面板,所以phantomjs模块提供了onConsoleMessage方法进行监听console的触发事件,进行输出。
var webPage=require('webpage');
var page=webPage.create();
page.onConsoleMessage(function(data){
console.log("the pass data is"+data);
});
page.open(url,function(status){
if(status){
console.log("hello world!");
}
phantom.exit();
});
- 9.webpage模块:includeJs()方法。
- includeJs(resourceURL,callback)方法提供了加载外部脚本的功能,使用phantomjs的includeJs对前端jser简直是福音的存在;在提取数据时可以直接加载jQuery库操作;以前在使用后端服务的Nodejs的Request和cheerio(服务端的jquery)脚本爬虫时会觉得提取XML或HTML中的数据时还担心前端jquery语法和cheerio不兼容;现在麻麻再也不用担心啦。
- includeJs方法在加载完成外部资源或者脚本之后就自动调用回调函数。
var webPage=require('webpage');
var page=webPage.create();
page.open("https://www.baidu.com",function(status){
page.includeJs("https://code.jquery.com/jquery-3.2.1.min.js",function(){
page.evaluate(function(){
$('.su').click();
});
});
});
- 10.webpage模块:render():
- render方法用于将网页保存成图片,参数就是要保存的图片路径。方法可以根据路径的后缀名,将网页保存成png、Gif、jpeg和pdf。方法可以接受一个配置对象,format字段用于图片格式,quality字段用于图片质量,最差是0,最好是100;renderBase64方法就是把截图png格式编码成Base64格式的字符串输出。
var webPage=require("webpage");
var page=webPage.create();
page.viewportSize={widtth:960,height:580};
page.open("http://www.baidu.com",function(status){
page.render("1.png",{format:"png",quality:"100"});
phantom.exit()
});
- 11.webpage模块:viewportSize,zoomFactor
- viewportSize属性是指定打开的浏览器窗口大小(如上节所示),即网页的初始化浏览器窗口大小。viewportSize的height字段是必须参数,不可省略。
- zoomFactor属性指定渲染页面的放大系数(1即100%)
var webPage=require('webpage');
var page=webPage.create();
page.viewportISize={
width:920,
height:480
};
page.zoomFactor=1;
page.render("1.png");
- 12.webpage模块:onResouceRequested
- onResourceRequested属性用来指定一个回调函数,当页面请求一个资源时,会触发这个回调函数。第一个参数是HTTP请求的数据对象,第二个参数是发出的网络请求对象。
- http请求数据:
- id:请求资源编号
- method:使用http方法
- url:所请求的资源url
- headers:http头信息数组
- 网络请求对象包含以下方法:
- abort():终止当前网络请求,网络请求终止会触发onResourceError回调函数
- changeUrl(newUrl):改变当前网络请求的URL
- setHeader(key,value):设置http头信息
var webPage=require('webpage');
var page=webPage.create();
page.onResourceRequested=function(requestData,RequestObj){
console.log('request'+requestData.id+'----'+JSON.stringify(requestData));
}
//过滤资源应用
page.onResourceRequested=function(requestData,RequestObj){
if((/http:\/\/.+?\.css$/gi).test(requestData['url'])){
console.log("abort this resource");
request.abort();
}
}
- 13.webpage模块:onResourceReceived
- onResourceReceived属性用于指定一个回调函数,当网页收到所请求的资源时,就会执行该回调函数。它的参数就是服务器发来的HTTP回应的元数据对象。如果http回应非常大,分成多个数据块发送,onResourceReceived会在多次收到数据块时触发回调函数。
- 元数据对象包含以下字段:
- id:所请求的资源编号
- url:所请求资源的url
- time:包含http回应时间的Date对象
- headers:http头信息数组
- bodySize:解压缩的收到的内容大小
- content-Type:接到的内容种类
- redirectURL:重定向URL(如果有的话)
- stage:对多数据块的http响应
- status:HTTP状态码,如404,200
- statusText:http状态信息,比如OK
var webPage=require('webpage');
var page=webPage.create();
page.onResourceReceived=function(response){
console.log("response"+response.status+response.statusText);
}
- 14.System模块:system模块可以加载操作系统变量,System.args就是参数数组。
- 在命令行下运行 phantomjs 1.js http://www.baidu.com;其中1.js就是下面的代码
var webpage=require('webpage')
var system=require('system');
var t,address;
//如果命令行没有给出网址
if(system.args.length===1){
console.log("the url address is need!");
phantom.exit();
}
t=Date.now();
address=system.args[1];
page.open(address,function(status){
if(status!=="success"){
console.log("failed to get webpage");
}else{
t=Date.now()-t;
console.log("Loading time"+t+"ms");
}
phantom.exit();
});
- 15.综合运用例子:
- 下面是请求http://www.360kan.com网址的示例:
var webPage=require('webpage');
//设置网页编码格式
phantom.outputEncoding="gbk";
var pageTab=webPage.create();
var tbUrl="http://www.360kan.com/";
//设置请求头信息
pageTab.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";
pageTab.open(tbUrl,function (status) {
//360kan网址的数据是动态加载的,这里等待2秒在执行其他操作。
setTimeout(function(){
pageTab.includeJs("http://code.jquery.com/jquery-3.2.1.min.js", function() {
pageTab.evaluate(function() {
var lists=$(".name");
for(i=0;i<lists.length;i++){
var list=lists[i];
console.log(lists.text()+"\n");
}
});
phantom.exit()
});
},2000);
})
pageTab.onConsoleMessage = function(msg) {
console.log('Page title is ' + msg);
};
- 16.Phantomjs官方翻译文档示例:
- setting.userAgent指定http请求的userAgent头信息
- setting.viewportSize:z指定浏览器窗口的大小
- clipRect:指定截图的大小,第一参数top(距离浏览器上面多少距离);第二参数是left(距离左边多少);width和height从字面可以知道是宽高大小。
var webpage=require('webpage');
var page=webpage.create();
page.setting.UserAgent="webkit/534.46 Mobile/9A405 safari/7534.48.3";
page.setting.viewportSize={width:400,height:600};
page.open("http://www.baidu.com",function(status){
if(status!=="success"){
console.log("load failed");
phantom.exit();
}else{
var title=page.evaluate(function(){
return document.title;
});
window.setTimeout(function(){
page.clipRect={top:0,left:0,width:600,height:400};
page.render(title+".png");
page.clipRect={left:0,top:600,width:400,height:400};
page.render(title+"1.png");
phantom.exit();
});
}
});
上面是phantomjs的常用使用方法,下一篇关于selenium2和phantomjs结合使用爬虫js延迟或者AJAX获取数据的提取方式实例。
资料参考来自:
1.阮一峰老师 phantomJS
2.腾云阁社区关于phantomjs使用