转载:https://www.oschina.net/translate/building-your-own-web-scraper-in-nodejs

从你的应用中收集数据有时候可能有点困难和艰辛。可能是缺少一个必须的API,或者是有太多的数据需要处理。这时候你就需要借助于web抓取。

不用说了,这可能是个法律雷区,所以要确保你没有逾越法律的边界。

目前有很多工具可以帮助你抓取内容,例如Import.io,但是有时这些工具并不能完全满足你的需要。又或者,像我一样,充满好奇心,希望深入地了解web抓取。

挑战

让我们从一个简单地挑战——网络爬虫开始,让这个爬虫爬取Techmeme,并获得一个当天热门新闻列表!

注意: 在这里我将会使用DZone,但在获取页面时会出现问题。后面会详细说明这个问题。

社会主义好
翻译于 1年前
0人顶
 翻译得不错哦!
 

机器设置

您只需要做很少的工作来完成安装。我假设您已经安装了Node.js(我的意思是谁没有安装呢!)。尽管我们并不直接使用PhantomJS,但是您依然需要安装它。版本2.0.1目前已经可以使用了——您可以从其官网下载或使用homebrew或其他等效的包管理器安装。

如果您使用具有homebrew的Mac,您可以这样安装PhantomJS

  1. brew install phantomjs

下载完成之后,您将需要用相同的方式安装CasperJS。您可以将CasperJS看做PhantomJS的伴侣。它实际上是给您提供相似的网页处理API。尽管它是为网页测试设计的。与PhantomJS相同,它具有丰富的功能使其也非常适合于抓取内容。

CasperJS允许我们编写JavaScript脚本。您可以通过在终端中输入casperjs以测试其是否正确安装并加入到PATH中。

社会主义好
翻译于 1年前
0人顶
 翻译得不错哦!
 

编写脚本

下面我们将编写一个新的JavaScript脚本文件。在我的例子中,我称其为index.js。您需要做的第一件事就是在您的代码中创建一个casper实例。您还需要加入依赖的模块并向其传递一些基本参数。

  1. var casper = require("casper").create({
  2. waitTimeout: 10000,
  3. stepTimeout: 10000,
  4. verbose: true,
  5. pageSettings: {
  6. webSecurityEnabled: false
  7. },
  8.     onWaitTimeout: function() {
  9.           this.echo('** Wait-TimeOut **');
  10.     },
  11.     onStepTimeout: function() {
  12.         this.echo('** Step-TimeOut **');
  13.     }
  14. });

当您等待一个元素可见时,上面的onWaitTimeout回调将会被调用。例如,点击一个按钮之后,waitTimeout将被超出。

现在,您可以启动casper实例并将其指向我们希望爬取的页面。

  1. casper.start();
  2.  
  3. casper.open("http://techmeme.com");

Casper使用一个可靠地框架来帮助您一步一步地运行所有任务。对于第一步,您将希望使用then函数。

  1. casper.then(function() {
  2.   //logic here
  3. });
  4. //start your script
  5. casper.run();

为了使Casper打开网页并按您的想法运行,您需要调用run函数。

社会主义好
翻译于 1年前
0人顶
 翻译得不错哦!
 

检查网页以获取想要的元素

当抓取到一个网页,您可以假设它具有特定的结构。在您编写脚本之前,可能已经浏览过了网页的源代码,或者已经使用开发者工具观察了页面对特定行为的变化。

所以,让我们开始于一个简单地逻辑,使用CasperJS维护系统确保一个特定的元素在继续之前处于合适的位置。如果元素不存在,脚本将会停止,但是至少您将会知道其为何停止。这个维护行为对于观察您之前抓取页面的变化是无价的,但是可能会与您之前见到的页面具有不一样的结构。

社会主义好
翻译于 1年前
1人顶
 翻译得不错哦!
 

如果您检查了Techmeme首页的元素,您将会注意到头条新闻部分在一个id为,topcol1的div中。

让我们使用维护功能确保这个元素存在:

  1. casper.then(function() {
  2.  
  3. this.test.assertExists("#topcol1");

如果这个元素不存在,测试(例如我们的脚本)将会停止,否则它将继续运行。

您还可以使用waitForSelector函数来获得更为细致的结果:

  1. this.waitForSelector("#topcol1",
  2.     function pass () {
  3.        console.log("Continue");
  4.     },
  5.     function fail () {
  6.         this.die("Did not load element... something is wrong");
  7.     }
  8. );

使用这个函数的优点就是它允许页面加载元素并一直等待到执行。您在初始配置中指定的waitTimeout将会被用于确定失败前等待多久。

注意:有时,使用CasperJS查找元素可能会出问题。使用capture()函数截取一个CasperJS看到的页面的截图。 
this.capture('screener.png');

社会主义好
翻译于 1年前
0人顶
 翻译得不错哦!
 

从页面中提取内容

下面,让我们看看怎样从页面中找出标题。首先,找到包含您需要的内容的元素,在我们的例子中,为class=ii的div。

CasperJS自带一个evaluate函数,可以让您在页面中运行JavaScript,并且您还可以让函数返回一个值以供进一步处理。

这个JavaScript写起来并没有什么不同,您可能注意到,在本例中,我使用的是原始的纯DOM方法,而不是jQuery,同样,如果您愿意,您也可以在evaluate函数中使用jQuery;

  1. var links = this.evaluate(function(){
  2. var results = []; 
  3. var elts = document.getElementsByClassName("ii");
  4. for(var i = 0; i < elts.length; i++){
  5. var link = elts[i].getElementsByTagName("a")[0].getAttribute("href");
  6. var headline = elts[i].firstChild.textContent;
  7. results.push({link: link, headline: headline});
  8. }
  9. return results; 
  10. });

如果您在evaluate函数中使用console.log语句,它们将会通过remote.message句柄打印到您的控制台,这将会在下一节中详细介绍。

社会主义好
翻译于 1年前
0人顶
 翻译得不错哦!
 

一旦运行结束,结果将会返回给您。您可以将它们写入文件系统,或者将它们打印到屏幕上:

  1. console.log("There were "  + links.length + " stories");
  2.  
  3. for(var i = 0; i < links.length; i++){
  4. console.log(links[i].headline);
  5. }

输出的结果如:

抓取中的错误处理

有时,您运行的JavaScript中可能存在错误,或者其对您抓取的页面的处理存在问题。这些情况中,您可以捕获错误并使用remote.message和page.error事件将其打印到控制台:

  1. casper.on('remote.message', function(msg) {
  2. this.echo('remote message caught: ' + msg);
  3. });
  4.  
  5. casper.on('page.error', function(msg, trace) {
  6. this.echo('Error: ' + msg, 'ERROR');
  7. });

您同样还能观察到即将请求的资源,这些资源的加载使用的是resource.error和resource.received事件:

  1. casper.on('resource.error', function(msg) {
  2. this.echo('resource error: ' + msg);
  3. });
  4.  
  5. casper.on('resource.received', function(resource) {
  6.     console.log(resource.url);
  7. });

社会主义好
翻译于 1年前
1人顶
 翻译得不错哦!
 

了解更多

本文只写了点关于使用CasperJS你所能做到的皮毛的东西。该项目的文档是完美的,所以要确保查看过 API ,看看你还可以用它来做些什么。

在本系列的下一篇文章中,我回来看看如何从网页上下载图片,而且我也会讨论下如何使用构建到CasperJS中的文件系统函数,其使用会受到比Node.js更多的限制。

使用 CasperJS 构建 Web 爬虫的更多相关文章

  1. 第三百二十九节,web爬虫讲解2—urllib库爬虫—ip代理—用户代理和ip代理结合应用

    第三百二十九节,web爬虫讲解2—urllib库爬虫—ip代理 使用IP代理 ProxyHandler()格式化IP,第一个参数,请求目标可能是http或者https,对应设置build_opener ...

  2. NodeJs+http+fs+request+cheerio 采集,保存数据,并在网页上展示(构建web服务器)

    目的: 数据采集 写入本地文件备份 构建web服务器 将文件读取到网页中进行展示 目录结构: package.json文件中的内容与上一篇一样:NodeJs+Request+Cheerio 采集数据 ...

  3. 使用EXtjs6.2构建web项目

    一.项目简介 众所周知ext是一款非常强大的表格控件,尤其是里边的grid为用户提供了非常多的功能,现在主流的还是用extjs4.0-4.2,但是更高一点的版本更加符合人的审美要求.因此,在今天咱们构 ...

  4. Web爬虫入门

    1.0示例学习:Web爬虫 public class WebCrawler { // 种子url private static String url = "http://www.cnblog ...

  5. 《深入浅出Node.js》第8章 构建Web应用

    @by Ruth92(转载请注明出处) 第8章 构建Web应用 一.基础功能 请求方法:GET.POST.HEAD.DELETE.PUT.CONNECT GET /path?foo=bar HTTP/ ...

  6. 基于MVC4+EasyUI的Web开发框架经验总结(2)- 使用EasyUI的树控件构建Web界面

    最近花了不少时间在重构和进一步提炼我的Web开发框架上,力求在用户体验和界面设计方面,和Winform开发框架保持一致,而在Web上,我主要采用EasyUI的前端界面处理技术,走MVC的技术路线,在重 ...

  7. Eclipse中使用maven构建web项目中遇到的问题

    构建过程参考: http://blog.csdn.net/smilevt/article/details/8215558/ http://www.cnblogs.com/dcba1112/archiv ...

  8. Node.js高级编程读书笔记 - 4 构建Web应用程序

    Outline 5 构建Web应用程序 5.1 构建和使用HTTP中间件 5.2 用Express.js创建Web应用程序 5.3 使用Socket.IO创建通用的实时Web应用程序 5 构建Web应 ...

  9. 高效构建Web应用 教你玩转Play框架 http://www.anool.net/?p=577

    Play 框架是一个完整的Web应用开发框架,覆盖了Web应用开发的各个方面.Play 框架在设计的时候借鉴了流行的 Ruby on Rails 和 Grails 等框架,又有自己独有的优势.使用 P ...

随机推荐

  1. sleep,yield,join,notify,wait,notifyAll区别

    1.  Thread.sleep(long) 和Thread.yield()都是Thread类的静态方法,在调用的时候都是Thread.sleep(long)/Thread.yield()的方式进行调 ...

  2. 在静态方法和非静态方法上加 Synchronized的区别

    Synchronzied 修饰非静态方法==>对象锁 Synchronzied 修饰静态方法==>其实是类锁,因为是静态方法,它把整个类锁起来了: 1.Synchronized修饰非静态方 ...

  3. KD-Tree学习笔记

    参考:https://trinkle23897.github.io/pdf/K-D%20Tree.pdf KD-Tree是一种维护K维空间点的类似BST的数据结构.绝大多数时候只用来维护二维空间的点, ...

  4. Trace 2018徐州赛区网络预赛

    题意: 每次给出一个点,然后就会形成两条线,如果后面的矩形覆盖了前面的边,那么这条边就消失了, 最后求剩下的边是多少 题目确保不会完全覆盖 也没有一个矩形在另一个矩形里面 即对于 X1,Y1  X2, ...

  5. 【bzoj1069】最大土地面积

    Description 在某块平面土地上有N个点,你可以选择其中的任意四个点,将这片土地围起来,当然,你希望这四个点围成的多边形面积最大. Input 第1行一个正整数N,接下来N行,每行2个数x,y ...

  6. Docker镜像加速==》阿里云加速器

    1.使用阿里云加速器加快获取docker官方的镜像 步骤一:如果没有阿里云账号,需要注册阿里云开发账号 https://dev.aliyun.com/ 步骤二:进入加速器页面获取加速信息 https: ...

  7. 洛谷P2480 古代猪文

    这道题把我坑了好久...... 原因竟是CRT忘了取正数! 题意:求 指数太大了,首先用欧拉定理取模. 由于模数是质数所以不用加上phi(p) 然后发现phi(p)过大,不能lucas,但是它是个sq ...

  8. 解决VMware虚拟机网络时长中断的问题

    1. 操作环境 VMware VMware® Workstation 14 Pro Windows Win7旗舰版 2. 操作过程   VMware虚拟机在使用一段时间后,经常会出现时常断网的情况,而 ...

  9. node爬虫入门

    爬虫其实就是模仿浏览器访问页面,然后把页面保存起来备用. 爬虫的方法,直接上代码: function getUrl(url,success,error){ let urlObj = urlParser ...

  10. IIS发布MVC出错

    一个MVC网站在发布到IIS上时,出现了这个问题: 然后解决办法: 然后应用程序池那里,自己点右键添加一个 新建完应用池之后选中点高级设置 最后,添加网站,添加网站的时候应用程序池选择自己刚刚新建的那 ...