zoukankan      html  css  js  c++  java
  • 爬虫部分技术要点浅析

    本来打算昨晚发的,结果园子又迁移......

      网络爬虫(Spider或Crawler),顾名思义,就是在互联网上爬行的虫子,那么这只虫子为什么要在网上爬行呢?很简单:收集信息。在互联网时代,谁掌握了信息谁就把握了主动权。曾经我一直觉得做搜索的公司都是慈善家,他们自己花钱为大众服务,真是太高尚了,直到我知道谷歌每年大半的盈利来自广告,我才明白那句名言——互联网上最昂贵的东西就是免费,因为它能让你轻易的接受,却无法舍弃。(我想多数人离开了搜索引擎,将在网络上寸步难行)

      好吧,扯多了,我们先看下下图。我们可以很容易的看出,网络爬虫的根本任务就是从互联网抓取数据,存入数据库或本地文件系统以供使用。

      

      从图中看来似乎一个网络爬虫的功能很简单,但是可不要小看这一个方框所包含的内容,它里边的很多步骤展开之后都包含着一方面技术(当然,菜鸟我就不怎么展开说了,水平不足,怕出丑),下图是一个普通爬虫的内部实现图:

      

      如图所示,往往一个完整的怕成包含两大部分:调度部分和作业部分。其中调度部分可以看做一个总控制器(准确的说通常总控线程包含调度线程),它完成爬虫的启动初始化(配置线程数,Url集合大小,加载Url种子、当前抓取进度、已抓取集合,以及其他配置信息)、运行时调度(为作业线程分配资源)、善后处理(当url集合为空时采取的策略等),有时候还要负责与外部系统交互(如分布式的情况下,一个爬虫将作为一个作业,而调度线程则需要和总控服务器交互信息)。而作业线程就是苦逼干活的了,完成的任务如图所示。

      从图中我们可以提出以下几个问题(都是粗浅的,但是对于实现一个爬虫却是基本的):

             1、如何从互联网请求数据

             2、作业线程的怎样实现?启动多少个合适?也调度线程如何交互?

             3、如何处理抽取出来的Url(爬取策略)?

             4、Url如何滤重?

      下边我们就一一来讨论:

    1、如何从互联网请求数据?

      在讨论这个问题之前我们先来思考一个问题:为什么我们输入url之后一按回车,浏览器就能将对应的页面显示出来?多数时候浏览器根据url向服务器发起请求(一般情况下使用Http协议,不懂的建议看看帅气的肖佳大大的系列文章:http://www.cnblogs.com/TankXiao/category/415412.html 。),将对应页面下载到本地,然后浏览器的解释器将页面源码解释为我们看到的图文元素,如下图。

      

      从上边的过程我们可以想到,我们只需要模拟浏览器想服务器发起请求即可。对于Java而言,这在多数情况下很容易实现的,Java本身提供了实现请求的对象,如HttpURLConnection,而且使用Apache的子项目HttpClient也能方便实现这些功能(当然熟悉Socket更好,一些情况下直接使用socket来实现不仅更灵活,而且能够在性能上有很大突破)。至于请求的具体实现,网上已有大量资料,但是提醒一点的是,针对对当前爬虫泛滥的情况,不少网站都在反爬虫上做了功夫(往往程序猿们爱爬的网站不想被别人爬,而且程序猿们的小爬虫通常不会遵守啥Robots.txt协议且极具破坏力,曾经就爬瘫过小网站,在此深感抱歉,希望贵网站内换个给力点的服务器以供菜鸟练手......),所以熟悉http等请求协议会使你事半功倍,至少搞定一些普通的请求没问题,我们要坚信互联网一条原则:所见必可得

      最后建议想研究这方面的菜鸟同胞们,学会使用chrome/firefix的Debugger和一些抓包工具(如fiddler2、Sniffer)是很有必要的。

    2、作业线程的怎样实现?启动多少个合适?也调度线程如何交互?

      想要实现一个良好的爬虫(甚至说一个可用的),必然要采用到多线程技术,这也是用java实现一个优秀系统必然设计的(很多时候你不知不觉就已经用到了)。至于实现的细节在此不再赘述。对于一个小型爬虫而言,我觉得应该至少实现三部分:调度、工作和日志(之所以强调日志是因为其对于我们掌控爬虫的状态是很有用的,一个不可控的程序听着就让人不爽)。其中调度和日志一般一个线程计可,而工作线程一般需要配置多个,这里建议小型爬虫使用java的线程池机制即可(为啥JobSearch里没有?额.....因为当时我还不会),可以节省很大功夫。

      那么一般我们应该启动多少个工作线程呢?我也不知道。这是个很难回答的问题,我们知道对于软件系统的性能最终会汇集到一个词:IO(磁盘IO和网络IO),而这有和硬件密切相关的。对已一个稳健性良好的程序,在PC和机房的小型机上跑,性能差距往往很明显。那么这个问题应该如何解决呢?这里就要提到优秀爬虫应该做到的一项原则:可配置度应该高。也就是说我们应该将想要经常改变的内容变为可配置的,这点在很多开源软件中很常见。如此一来我们可以将工作线程池的大小在配置文件中定义,在部署之后根据服务器的运行情况来调整即可。

      至于工作线程与调度线程如何交互,其实就是通过待抓取Url集合(通常是队列)和已抓取Url集合(用以滤重,有其他更好的替代方案,之后会讲到)。调度线程一般维护全局的Url抓取队列,而工作线程每次从中取出一条或几条进行抓取。这里需特别注意的就是线程间的资源竞争(Url),所以Url队列需特别保护(例如同步变量或者使用ThreadLocal)。

      好吧,写的速度太慢了,俩小时才写了这么多。今天就先讲到这了,后两个问题改天补上吧。

      最后共享一篇收藏的文章,里边讲的比我这菜鸟级的强多了。另外最经看了hadoop的一些初级的基本原理,感觉其很多实现思想对我深有启发,大家没事也可以了解下。

      共享文档(版权属其原作者所有):搜索引擎系统学习与开发总结

     

     
     
  • 相关阅读:
    高级特性(4)- 数据库编程
    UVA Jin Ge Jin Qu hao 12563
    UVA 116 Unidirectional TSP
    HDU 2224 The shortest path
    poj 2677 Tour
    【算法学习】双调欧几里得旅行商问题(动态规划)
    南洋理工大学 ACM 在线评测系统 矩形嵌套
    UVA The Tower of Babylon
    uva A Spy in the Metro(洛谷 P2583 地铁间谍)
    洛谷 P1095 守望者的逃离
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/3017961.html
Copyright © 2011-2022 走看看