欢迎你们前往腾讯云技术社区,获取更多腾讯海量技术实践干货哦~javascript
做者:李大伟html
Phantomjs官网介绍是:不须要浏览器的完整web协议栈(Full web stack No browser required),也就是常说的无头浏览器——或者好听点叫作:无界面的web解析器。java
因为“无头”——免去了渲染可视化的网页界面,她的速度要比通常的浏览器快很多,又由于她是完整的web协议栈,因此不只仅提供了JavaScript API,还完整的支持各种web标准:DOM操做、CSS选择器、JSON、Canvas和SVG,以及文件系统API和操做系统API。此外她还提供不少web事件监控处理接口(event handle),这一点也是Phantomjs区别于selenium等web自动化测试工具的关键所在,具体的将在后续安全检测中详细说明。react
笔者将Phantomjs的特征汇总以下表:jquery
The WebPage APIweb
The System APIchrome
The FileSystem API浏览器
The WebServer API安全
鉴于以上特色,咱们就会发现Phantomjs特别适合用来写!爬!虫!bash
支持JavaScript即可以动态加载资源,或完成一些模拟人类的动做;支持DOM操做即可以结构化页面;CSS的支持即可以快捷方便的完成页面文档的渲染,供咱们保存图片或处处PDF;支持JSON、Canvas和SVG更是对与数据或多媒体页面处理的加分项;同时文件系统API的提供,也让咱们很方便的将处理结果格式化存储起来。
下载Phantomjs后,直接运行Phantomjs就进入了交互模式,这时咱们能够把她当作一个JavaScript解释器使用,运算、js方法、使用window.navigator对象查看“浏览器”信息等等,你们若是安装了Phantomjs能够随意输入一些命令感觉一下。感觉结束后输入phantom.exit()`退出。
图:REPL 模式下的 Phantomjs
若是是初学js的同窗,这个模式可能会比chrome的console栏更大一些,方便用来练习js命令。此外,这个这个模式并不经常使用,咱们更多的是将Phantomjs看作一个二进制工具来使用。
这也是Phantomjs最经常使用的一个模式:phantomjs /scripts/somejavascript.js来运行一个JavaScript脚本。脚本中可使用Phantomjs提供的各种API(KM的markdown语法不支持页内锚点,详见文章前部分的“Phantomjs提供的API汇总”);
建立一个webpage的实例,而后使用open方法打开腾讯网首页,若是返回值是成功,则日志打印出网页标题,以后退出。
/****************************************************************
* create an instance of the webpage module
* get the page and echo the page's title * file: somejavascript.js * auther : Taerg * date : 12/05/2017 *****************************************************************/ var page = require('webpage').create(); // open the webpage // defined callback: check the status and echo teh status page.open("http://www.qq.com", function(status) { if ( status === "success" ) { console.log("Page load success.The page title is:"); console.log(page.title); } else { console.log("Page load failed."); } phantom.exit(0); }); 复制代码
固然,咱们也能够用page.content来获取页面的全部内容,使用page.cookies来获取cookie。
以下,咱们获取访问王者荣耀网站时的cookie,并使用键值对的方式打印在log里:
/****************************************************************
* create an instance of the webpage module
* echo the cookies
* auther : Taerg
* date : 12/05/2017
*****************************************************************/
var page = require('webpage').create();
console.log(1);
page.open("http://www.qq.com/", function(status) {
if (status === 'success') {
var cookies = page.cookies;
for(var i in cookies) {
console.log(cookies[i].name + '=' + cookies[i].value);
}
}
phantom.exit(0);
});
复制代码
对应的输出为:
图:phantomjs_getcookie
Phantomjs做为无头“浏览器“,固然对JavaScript的支持也是极好的。以下,咱们定义了一个简单的函数,来获取页面标题后返回。只须要简单的调用page.evaluate()来执行这段JavaScript代码便可。
/****************************************************************
* create an instance of the webpage module
* include system module
* auther : Taerg
* date : 12/05/2017
*****************************************************************/
var system = require('system');
var url = system.args[1];
console.log(url);
var page = require('webpage').create();
page.open(url, function(status) {
if ( status === "success" ) {
var title = page.evaluate(function () {
return document.title;
});
console.log(title);
}
})
phantom.exit(0);
复制代码
若是以为本身用JavaScript代码来重复造轮子太麻烦,咱们也能够在Phantomjs中使用第三方的JavaScript库。Phantomjs为咱们提供了2中使用第三方库的方法:
两者经常混用,主要的区别在于injectJs是阻塞加载,而includeJs是动态加载。injectJs能够理解为代码执行到这里时,程序阻塞,加载这个js文件到内存后,程序继续运行,在操做页面时不会对这个文件发起请求。而includeJs则是在加载页面用到此js文件时动态加载文件。
实例代码以下:
/****************************************************************
* create an instance of the webpage module
* load third part js lib
* auther : Taerg
* date : 12/05/2017
*****************************************************************/
var page = require('webpage').create();
// open the webpage
page.open("http://www.qq.com", function(status) {
page.injectJs('jquery321.js');
//different with page.includeJs
if (status === 'success') {
var aoffset = page.evaluate(function() {
return (typeof jQuery === 'function') ? jQuery.fn.jquery : undefined;
});
console.log(aoffset);
}else{
console.log('open error');
}
phantom.exit(0);
});
复制代码
输出以下:
咱们先inject了版本号为3.2.1的本地jQuery文件,以后即可以使用jQuery的方法来查看jQuery版本。固然,这只是验证jQuery加载成功,在咱们彻底可使用其余jQuery提供快捷方法来实现咱们的需求。
在咱们处理页面时,经常会有保存页面截图的需求,好比:保存页面BUG的样子、关键信息的留证等等。这时咱们就可使用Phantomjs的page提供的render方法,她支持将完整的页面(自动滚屏截图)、指定区间的页面保存下来(.png, .pdf, .jpg等格式均支持)。
以下,咱们想获取天气网站”个人天气“详情,而不去关注网页其余各类新闻和广告,咱们只需指定区间,而后保存截图便可:
/****************************************************************
* phjs_clip.js
* get the weather pic
* auther : Taerg
* date : 12/05/2017
*****************************************************************/
var page = new WebPage();
page.open('http://www.weather.com.cn', function (status) {
if (status !== 'success') {
output.error = 'Unable to access network';
} else {
page.clipRect = {
top: 200,
left: 750,
width: 300,
height: 500
}
page.render('weather.png');
console.log('Capture saved');
}
phantom.exit();
});
复制代码
保存的图片以下所示:
图:phantom_get_weather
当咱们正常使用浏览器访问https://media.om.qq.com/media/5054676/list时,一切正常,以下图:
图:safari_get_omqq
根据这套反爬虫做者的解释,客户端通过JavaScript计算出来一个票据,包含在cookie将在服务端再次验证,验证经过则返回数据,验证不经过则不返回数据。以下图所示:
图:anti_spide
下面咱们经过脚原本自动拉去这个页面数据试试
首先咱们先用最简答的curl来get这个页面看看能都拿到这个页面的数据:
图: curl_get_omqq
如上图所示,被反爬虫系统拦截了。
咱们再用Python试试,使用最通用的“HTTP for humans”的requests.get请求:
图: request_get_omqq
能够看到依旧会被反爬虫机制拦截。
经过人工浏览器访问、抓包分析,咱们能够看到:
1 . 人工访问这个网页一共发起了6条请求 2 . 第1条请求时直接请求目标url,因为没有合法票据,返回403。同时在403页面中包含了2个JavaScript文件
图: load_js
3 .接下来的2个请求分别为对403页面中的JavaScript脚本进行加载
4 .加载运行完毕后,得到了合法票据并添加进cookie中再次发起请求,产生了第4条请求。以下图:
图:omqq_signiture
5.第4条请求带有合法票据,所以没有被403forbidden掉,而是增长一个客户id标示后302跳转到了数据页面。以下图:Set-cookie中添加了id签名。
图: redirect
6 .此时,cookie中已经包含有了合法的签名以及客户id,请求到了JSON数据。获得了正常的页面:
图: safafi_get)omqq
至此,咱们就能够根据前面的分析使用Phantomjs来逐步模拟人工请求,从而绕过反爬虫系统。先看代码:
/****************************************************************
* phjs_antispider.js
* anti-anti-spider script for https://media.om.qq.com/media/5054676/list
* auther : Taerg
* date : 12/05/2017
*****************************************************************/
var page = require("webpage").create();
var system = require("system")
url = system.args[1];
headers = {};
page.customHeaders = headers;
page.settings = {
javascriptEnabled: true,
userAgent: 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/37.0.2062.124 Safari/537.36',
};
page.viewportSize = {
width: 1024,
height: 768
};
page.open(url,
function(status) {
page.injectJs('jquery321.js');
if (status !== 'success') {
console.log('Unable to access network');
} else {
page.evaluate(function() {
var allElements = $('*');
for ( var i = 0; i<allElements.length; i++ ) {
if (allElements[i].href) {
javascript_code = allElements[i].href.match("javascript:(.+)");
if (javascript_code){
console.log(javascript_code[0]);
eval(javascript_code[0]);
}
}
}
});
}
window.setTimeout(
function() {
console.log("crawl_content:"+page.content+"content_end")
phantom.exit()
},
1000
);
phantom.exit();
});
复制代码
在上述代码中:
运行结果以下:可见,咱们的请求已经绕过了反爬虫机制。
图: phantomjs_get_omqq
卧槽,我就是个开发,你跟我说抓包分析啥的我不会啊!!宝宝只想爬点数据而已啊…
那就用三行代码来实现吧:
/****************************************************************
* crawl the anti-aipder website: om.qq.com
* auther : Taerg
* date : 17/05/2017
*****************************************************************/
var casper = require("casper").create();
casper.start('https://media.om.qq.com/media/5054676/list', function() {
require('utils').dump(JSON.parse(this.getPageContent()));
});
casper.run(function() {
this.exit();
});
复制代码
结果以下:
图:casper_get_omqq
这三行代码不只成功绕过了反爬虫的限制,并且自带的JSON方法也将也数据结构化显示(存储),对于复杂爬虫的开发能够极大的简化开发复杂度。
这三行代码中用到的就是—CasperJS。
CasperJS官方自称是一个开源的导航脚本和测试工具,但实际用起来爽的不行不行的。具体包括:
此外,CasperJS最为强大的地方在于我在这里给你们简单介绍以后,我就不用再说什么了,CasperJS拥有极其丰富的文档及实例代码。这一点对比核心文档仍是TODO,须要咱们来撰写各种文档的Phantomjs来讲友好太多了。
###相关阅读
爬虫实战:爬虫之 web 自动化终极杀手 ( 上) Scrapy 对接 Splash 精通 Python 网络爬虫:网络爬虫学习路线 此文已由做者受权腾讯云技术社区发布,转载请注明文章出处
原文连接: https://www.qcloud.com/community/article/636391