CasperJS is a navigation scripting & testing utility for the PhantomJS (WebKit) and SlimerJS (Gecko) headless browsers, written in Javascript.

PhantomJS是基于WebKit内核的headless browser

SlimerJS则是基于Gecko内核的headless browser

Headless browser: 无界面显示的浏览器,可以用于自动化测试,网页截图,JS注入,DOM操作等等方面,是一种非常新型的web应用工具。虽然这种浏览器没有任何界面输出,但在很多方面都可以有非常广泛的应用。整篇文章将会介绍使用Casperjs进行网页抓取(网络爬虫)的应用,本文仅仅是起到一个抛砖引玉的作用,实际上headless browser技术的应用会非常广泛,甚至又可能深刻影响web前后端技术的发展。

本文用一个著名的网站【豆瓣网】“开刀”(仅仅是研究学习使用,希望该站不要找我麻烦),来试验一下强大的Headless Browser网页抓取技术的强悍。

第一步,安装Casperjs 打开CasperJS的官网http://casperjs.org/,下载最新稳定版本的CasperJS并安装,官网有非常详细的文档,是学习CasperJS最好的第一手材料。当然了,如果安装了npm,也可以直接通过npm安装。同时,这也是官方推荐的安装方法。关于安装就不多介绍了,官方文档介绍得非常详细。

 npm install casperjs
node_modules/casperjs/bin/casperjs selftest

第二步,分析目标网站的列表页的网页结构 通常内容类网站都是分成列表页面和详细内容页面。豆瓣网也不例外,我们先来看看豆瓣的列表页长什么样。分析以后发现豆瓣电影网的列表页是这样的,首先可以点排序的规则,翻页不是像传统的网站通过页码来翻页,而是点击最后面的加载更多,这样的网页,传统的爬虫程序往往就歇菜了,或者实现起来非常复杂。但是对于headless browser技术,这个都是小Case。通过分析网页就可以看到点击这个【加载更多】这个位置就能够不断得显示跟多影片信息。

第三步,开始写代码获取影片详情页的链接信息 我们就不客气了,模拟点击这个地方,收集超链列表, 下面的代码就是获取链接的代码。引用并创建casperJS对象,如果网页需要插入脚本可以在casper对象生成的时候在ClientScript部分引用要注入网页的脚本,为了加快网页的加载速度,我们禁止下载图片和插件:

  pageSettings: {
loadImages: false, // The WebPage instance used by Casper will
loadPlugins: false // use these settings
},


完整的获取详情页链接的代码,这里模拟点击【加载更多】并循环50次。其实循环可以进行改进,【判断 while(没有”加载更多”) then( stop)】,获得后用require('utils').dump(….)输出链接列表。保存下面的代码为getDoubanList.js, 然后运行 casperjs getDoubanList.js 就能够获得并输出该分类下所有的详情页链接。

 1 phantom.outputEncoding="uft8";
var casper = require('casper').create({
// clientScripts: [
// 'includes/jquery.js', // These two scripts will be injected in remote
// 'includes/underscore.js' // DOM on every request
// ],
pageSettings: {
loadImages: false, // The WebPage instance used by Casper will
loadPlugins: false // use these settings
},
logLevel: "info", // Only "info" level messages will be logged
verbose: false // log messages will be printed out to the console
}); casper.start("https://movie.douban.com/explore#!type=movie&tag=%E7%BB%8F%E5%85%B8&sort=recommend&page_limit=20&page_start=0", function () {
this.capture("1.png");
}); casper.then(function () {
this.click("a.more",10,10);
var i = 0;
do
{
i ++;
casper.waitForText('加载更多', function() {
this.click("a.more",10,10);//this.capture("2.png"); // read data from popup
});
}
while (i<50);
}); casper.then(function () {
require('utils').dump(this.getElementsAttribute('div.list-wp div.list a.item', 'href'));
'href')));
});
casper.waitForText('加载更多', function() {
this.capture("3.png"); // read data from popup
});
casper.run();

GetDoubanList.js

我使用了Nodejs来调用casperjs(用其他的语言比如Python,Java调用也是可以的,CasperJS并不是一个完整的系统,所以多线程,文本处理,数据库还是需要依赖其他的语言或者工具),并把结果输出到文件里保存,当然把结果放到数据库里也没有问题,但是这里为了简化,就不展开了(实际的应用中我是用的MongoDB)。Nosql数据库非常适合存放抓取下来的非结构化数据存储。

   //var fs = require("fs");
//var S = require("string");
var url = 'mongodb://localhost:27017/test';
//var trim = require('trim.js');
//include recode url module
var record = require('./RecordUrl'); ///Program running block/////////////////////////////////////////////////////////////////////
const spawn = require('child_process').spawn;
const urllist = spawn('casperjs', ['casper3_more.js']);
var strUrls = ""; urllist.stdout.on('data', (data) => {
console.log(data.toString());
strUrls = strUrls + data.toString(); }); urllist.stderr.on('data', (data) => {
console.log(data);
}); urllist.on('exit', (code) => {
console.log(`Child exited with code ${code}`);
var urlData = JSON.parse(strUrls);
var content2 = "";
for(var key in urlData){
if (content2 != "") {
content2 = content2 + "\r\n" + urlData[key];
}
else {
content2 = urlData[key];
}
}
var recordurl = new record.RecordAllUrl();
recordurl.RecordUrlInText(content2);
console.log(content2);
});

GetAllUrls

引用的RecordUrl模块,存MongoDB这一部分没有写,大家可以自行完成。
 exports.RecordAllUrl = RecordUrl;
var fs = require('fs');
function RecordUrl() {
var file = "d:/urllog.txt";
var RecordUrlInFile = function(theurl) { fs.appendFile(file, theurl, function(err){
if(err)
console.log("fail " + err);
else
console.log("写入文件ok");
});
};
var RecordUrlInMongo = function() {
console.log('Hello ' + name);
};
return {
RecordUrlInDB: RecordUrlInMongo,
RecordUrlInText: RecordUrlInFile
} ;
};

RecordUrl

第四步,分析详情页面并编写详情页面抓取程序

到这一步大家就已经获得了要抓取的详情页面的列表了,现在我们打开一个电影详情页来看看结构如何,分析下各个信息如何抓取。对于信息的抓取必须要综合使用DOM,文本处理和JS脚本等技术。我想获得这部分的信息,包括导演,编剧,评分等等。在本文就不重复了,这里仅抽取几个信息项例子演示。

1. 抓取导演列表:导演列表的DOM CSS selector  'div#info span:nth-child(1) span.attrs a' , 我们使用了function getTextContent(strRule, strMesg)  这个方法去抓取内容。

 phantom.outputEncoding="GBK";
var S = require("string");
var casper = require('casper').create({
clientScripts: [
'includes/jquery.js', // These two scripts will be injected in remote
'includes/underscore.js' // DOM on every request
],
pageSettings: {
loadImages: false, // The WebPage instance used by Casper will
loadPlugins: false // use these settings
},
logLevel: "info", // Only "info" level messages will be logged
verbose: false // log messages will be printed out to the console
}); //casper.echo(casper.cli.get(0));
var fetchUrl='https://movie.douban.com/subject/25662329/', fetchNumber;
if(casper.cli.has('url'))
fetchUrl = casper.cli.get('url');
else if(casper.cli.has('number'))
fetchNumber = casper.cli.get('number');
casper.echo(fetchUrl); casper.start(fetchUrl, function () {
this.capture("1.png");
//this.echo("启动程序....");
//this.echo(this.getHTML('div#info span:nth-child(3) a'));
//this.echo(this.fetchText('div#info span:nth-child(1) a')); //抓取导演
getTextContent('div#info span:nth-child(1) span.attrs a','抓取导演'); }); //get the text content of tag
function getTextContent(strRule, strMesg)
{
//给evaluate传入参数
var textinfo = casper.evaluate(function(rule) {
var valArr = '';
$(rule).each(function(index,item){
valArr = valArr + $(this).text() + ',';
});
return valArr.substring(0,valArr.length-1);
}, strRule);
casper.echo(strMesg);
require('utils').dump(textinfo.split(','));
return textinfo.split(',');
}; //get the attribute content of tag
function getAttrContent(strRule, strMesg, Attr)
{
//给evaluate传入参数
var textinfo = casper.evaluate(function(rule, attrname) {
var valArr = '';
$(rule).each(function(index,item){
valArr = valArr + $(this).attr(attrname) + ',';
});
return valArr.substring(0,valArr.length-1);
}, strRule, Attr);
casper.echo(strMesg);
require('utils').dump(textinfo.split(','));
return textinfo.split(',');
}; casper.run();

GetDirectors

2. 抓取制片国家和地区,这个信息使用CSS selector抓取会有困难,原因分析网页后就可以发现,首先这个信息不是放在一个<span>标签里面, 而且“美国”这个文本直接在<div id=’info’>这个高层级的元素里。对于这样的信息我们采用另外一种方式,文本分析和截取,首先映入String模块var S = require("string"); 这个模块也是要另外安装的。然后抓取整块的信息,然后用文本截取:

    //影片信息全文字抓取
nameCount = casper.evaluate(function() {
var valArr = '';
$('div#info').each(function(index,item){
valArr = valArr + $(this).text() + ',';
});
return valArr.substring(0,valArr.length-1);
});
this.echo("影片信息全文字抓取");
this.echo(nameCount);
//this.echo(nameCount.indexOf("制片国家/地区:")); //抓取国家
this.echo(S(nameCount).between("制片国家/地区:","\n"));

GetCountry

其他信息可以类似获取。

第五步,将抓取到的信息存储并作为分析的源,推荐使用MongoDB这类NoSql数据库存储,比较适合存放这样的非结构数据,而且性能更优。

基于Casperjs的网页抓取技术【抓取豆瓣信息网络爬虫实战示例】的更多相关文章

  1. Python使用Scrapy框架爬取数据存入CSV文件(Python爬虫实战4)

    1. Scrapy框架 Scrapy是python下实现爬虫功能的框架,能够将数据解析.数据处理.数据存储合为一体功能的爬虫框架. 2. Scrapy安装 1. 安装依赖包 yum install g ...

  2. 网页调试技巧:抓取马上跳转的页面POST信息或者页面内容

    http://www.qs5.org/Post/625.html 网页调试技巧:抓取马上跳转的页面POST信息或者页面内容 2016/02/02 | 心得分享 | 0 Replies 有时候调试网页或 ...

  3. Python数据抓取技术与实战 pdf

    Python数据抓取技术与实战 目录 D11章Python基础1.1Python安装1.2安装pip1.3如何查看帮助1.4D1一个实例1.5文件操作1.6循环1.7异常1.8元组1.9列表1.10字 ...

  4. Python爬虫实战---抓取图书馆借阅信息

    Python爬虫实战---抓取图书馆借阅信息 原创作品,引用请表明出处:Python爬虫实战---抓取图书馆借阅信息 前段时间在图书馆借了很多书,借得多了就容易忘记每本书的应还日期,老是担心自己会违约 ...

  5. 爬虫抓取页面数据原理(php爬虫框架有很多 )

    爬虫抓取页面数据原理(php爬虫框架有很多 ) 一.总结 1.php爬虫框架有很多,包括很多傻瓜式的软件 2.照以前写过java爬虫的例子来看,真的非常简单,就是一个获取网页数据的类或者方法(这里的话 ...

  6. Windows桌面共享中一些常见的抓屏技术

    1. BitBlt 我想做Windows开发应该都知道这个API, 它能实现DC间的内容拷贝, 如果我们把源DC指定成Monitor DC或是桌面DC, 它就能实现抓屏功能. 对于通过这种方式的抓屏, ...

  7. Windows抓屏技术

    Windows桌面共享中一些常见的抓屏技术 1. BitBlt   我想做Windows开发应该都知道这个API, 它能实现DC间的内容拷贝, 如果我们把源DC指定成Monitor DC或是桌面DC, ...

  8. Python爬虫实战六之抓取爱问知识人问题并保存至数据库

    大家好,本次为大家带来的是抓取爱问知识人的问题并将问题和答案保存到数据库的方法,涉及的内容包括: Urllib的用法及异常处理 Beautiful Soup的简单应用 MySQLdb的基础用法 正则表 ...

  9. 测试开发Python培训:抓取新浪微博抓取数据-技术篇

    测试开发Python培训:抓取新浪微博抓取数据-技术篇   poptest是国内唯一一家培养测试开发工程师的培训机构,以学员能胜任自动化测试,性能测试,测试工具开发等工作为目标.在poptest的se ...

随机推荐

  1. 网页解析的全过程(输入url到展示页面)

    1.用户输入网址,浏览器发起DNS查询请求 用户访问网页,DNS服务器(域名解析系统)会根据用户提供的域名查找对应的IP地址. 域名解析服务器是基于UDP协议实现的一个应用程序,通常通过监听53端口来 ...

  2. HDU 4081 Qin Shi Huang's National Road System 次小生成树变种

    Qin Shi Huang's National Road System Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/3 ...

  3. 黑科技--位集--bitset

    自从上次网赛发现这么个东西之后,深深地感受到了bitset的强大,0.0. 正常的bool占用1字节空间,bitset可以把这个缩到1bit,空间上8倍优化.正常用起来可能会跟位运算状态压缩类似,但是 ...

  4. ubuntu中mysql修改编码utf8

    摘要:Ubuntu Server 服务器下使用apt-get 命令安装的mysql,默认不是utf8.在这里记录一下如何将编码修改成utf8. 办法解决: 1.查看mysql编码 show varia ...

  5. Struts2 JSP中将list,set ,Map传递到Action然后遍历(三十五) - 雲淡風輕 - ITeye技术网站

    1.使用Strut2的的集合对象:在jsp初始化action中的list然后提交到action2.使用Struts标签,实现多个用户同时注册(注意属性配置文件)3.pojo package com.s ...

  6. Education Round16

    A题:题意:给定国际象棋king的坐标,求能向几个方向移动分析:处理一下边界情况,其他的都是8 #include <iostream> #include <cstdio> #i ...

  7. 使用RGBa和Filter实现不影响子元素的CSS透明背景

    点击查看原文 问题 如果我们想要一个元素拥有半透明的背景,我们有两个选择: 使用CSS和 opacity 做一张 24-bit PNG 背景图片 在CSS中使用opacity有两个问题,一是为了适应所 ...

  8. JS中获取和操作iframe

    一.需求与遇到的问题 在网站的后台管理中使用了iframe框架布局,包括顶部菜单.左侧导航和主页面.需求是:点击主页面上的一个按钮,在顶部菜单栏的右侧显示“退出”链接,点击可退出系统. 我的思路是:在 ...

  9. Mac上ssh无法登录的问题

    今天起来发现阿里云ssh无法登录了 出现一条警告: WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED! 开始打算清理know_hosts发现失败,清了根本 ...

  10. laravel安装excel功能

    原文安装链接:https://github.com/Maatwebsite/Laravel-Excel 代码如下: if ($rows = DB::connection('glist')->ta ...