网络爬虫之反爬小综述

近日在网络爬虫、不少群友提出各种各样的网络遇到的反爬的问题,现就该方面做一个综述性的介绍,多为自行总结之所得,因为本人主攻Java方向,下文中多会用java词汇来描述问题,望请且看且指教。

兵家有云,知己知彼, 百战不殆。故下边分网络爬虫作法、优缺点对比、服务器端反爬策略制定、爬虫设计之反爬设计。

一、网络爬虫的一般作法

  (1)基于Socket通信编写爬虫,这是相对最低层的方式,它可以完全控制Input/Output等,但对编程水平有很大考验,一般为了简单其鉴,多是基于第三方封装的网络包来做,而非直接基于socket编程。

       ps: socket不是一种通信协议,而是一种实现上下层通信的通讯机制,它衔接着如上层http协议和下层tcp/ip协议的通信与转换,是典型的通讯实现的简化和解耦。很多人在此有误解,特此一提。

  (2) 基于HttpURLConnection类编写爬虫,这是java.net包中为解决网络通信封装的核心类,它的底层也是基于socket实现。它可以方便控制,但代码依然偏大,作为学习和测试等很好,但做项目时并不是很好的选择。

  (3)基于apache的HttpClient包编写爬虫,这是目前java程序员编写网络爬虫首选的方案,版本更新、社区资源、易用性等都不错,是初学者和专业程序员都应该掌握的。

   (4) 基于phantomjs之类的无头(无界面)浏览器做二次开发实现爬虫目的,webkit也是不错的选择,但它为c/c++编写调用起来较方便,但被java来调用还要编译dll、jna之类的比较烦锁,所以很少有java程序员调用直接用webkit内核做爬虫。

而phantomjs在webkit基础之上提供了简明、易用的JavaScript api接口,成为很多java程序员的爬虫利器,更多细节可参考本博客的前几篇博文中有关于phantomjs的一个专门讲解,并可以在文章开头提到的群内获取相应的二次开发的爬虫工具。

说到无头浏览器,必须要说到htmlunit包,它是java基于Rhinojs的js引擎实现的无头浏览器,其时间较长知名度较高,但易用性、稳定性都比较弱,所以慢慢被ITers给抛弃了,如果不拿它做爬虫,而拿它做测试,还是个不错的利器。

casperJs是基于phantomjs做的二次开发,主要是针对一些phantomjs的api二次封装,易用程序再次提高很大比例,但作为学习和开发我选择了phantomjs,各有所好,可以多方尝试。

  (5)基于Selenium或是WebDriver之类的有头(有界面)浏览器做爬虫,用java基于二者之类的库,可以直接操作浏览器,当然该浏览器肯定是所在的主机已经安装完成,其效果是跟用户的行为一模一样的去进行浏览器操作,从而在程序处拿到各相关的数据进行解析、存储等达到爬虫的效果。

二、各爬虫实现的优缺点

 (1)爬虫效率(时间复杂度)

  上边所述的基于sockiet、httpurlconnection、httpclient等来做的执行效率显然要高于基于浏览器,原因在于它少去了加载一些无用的图片、js等之类的资源,最大限制的直接获取想要得到的数据。

  而相反基于浏览器的爬虫,不管是无头还是有头,它们都基于一次请求所引起的一系统URL发出请求,即像浏览器一样的去加载资源,两者的区别主要在于有没有界面去展示出来,这一点对资源、效率的影响很大。鉴于此,无头浏览器的效率是要高于有头浏览器的。     

 (2)资源占用(空间复杂度)

   跟爬虫效率的原因相似,因为加载的东西少,所占的内存、cpu等都会少很多,所以依然是不基于浏览器的占优。

 (3)抓包分析代价(学习成本)

    像前三者,都是要了解了整个的所要抓取的站点的URL请求流的过程,所以抓包分析的代价是很高的,复杂度和难度跟站点的设计成正比,关于抓包分析可以参考本博客的前边几篇博文,有相关专门介绍。

    而基于有头或无头的浏览器,就要省很多事,它是最大限制的去模拟人的,所以你只需要知道入口、出口等就可以了,中间的过程,可以通过自身提供的回调函数去调用等,相对要简单很多,这也是很多人基于phantomjs做二次开发爬虫,主要是因为简洁、开发效率高。

三、服务器端反爬策略

一些站点对于网络爬虫是有爱有恨,爱在于带来了流量,在做站点的流量统计等时,会有一些小优势;恨在于有些爬虫设计太差,请求过猛,使多很站点无法正常访问。

也是基于这些原因,服务器也会制定各种各样的反爬策略,双向保护,即不能误伤不是爬虫的,也不能让爬虫太肆无忌惮。一般的反爬策略及反爬的执行都是实时的,不会是延时或是离线的,那样没什么意义。针对不同的站点形式,会有不同的反爬策略。下边统一概要说下。

(1)基于访问的来源IP反爬

一些站点,像百度,它更多的是面向无百度帐号的访问请求,而很多爬虫看重百度的搜索数据资源,此时百度会选择基于IP的请求频率做限制,一般是单位时间内。

据我用httpclient和phantomjs实现的百度爬虫实测,百度对于非浏览器形式的反爬是基于IP的访问频率来做反爬行为,例如单IP达到每秒2个请求一段时间就会很快被反爬掉,如验证码、拒绝服务等,而百度对于phantomjs实现的爬虫,我每天的请求量达20-30万次/天时,几乎没有反爬。鉴于此也可以发现,百度的反爬,并非单靠IP的请求频率,而是有其它的辅助判定爬虫的方法,如请求的前后资源是否被请求过等等。

(2) 基于访问的来源username反爬 

 像新浪微博类,需要登陆后才可访问到所需要的资源,所以很多爬虫需要模拟登陆后爬取。此时的反爬设计应该是基于用户和来源IP做双向的反爬监测。

 经过自行研发的新浪微博爬虫项目实测,用户每2-3分钟切换一次,然后每秒请求5-15次数据页,单IP的情况下也不会被反爬,只有在元搜索页这种情况下极少情况下会出现验证码,每天可稳定获取100万条微博数据。

 在有代理服务器的情况下,结合多用户自动切换,在不异地登陆的情况下,可以达到任意爬取。但当有异地出现时,要人工打码完成验证码的输入过程,会影响抓取频率。

(3)基于请求流的实时统计等方式实现反爬

     在用socket、httpurlconnection、httpclient等写的爬虫,是建立在抓包分析后,得到请求的关键URL请求流基础之上的,所以会造成很多的请求是不在请求范围中的,这些不在范围中的请求,多跟数据获取无关,但对服务器确实有很大的影响的,尤其实是富浏览器端如此盛行的当下。如一些ajax请求、广告请求、回调函数、正常的相关请求资源连接等,都会被分析给过滤掉,这也是为何该类爬虫的执行效率高的实际原因。

     正因为上述原因,只要在服务器对访问记录做一些相关的统计追踪,就可以很容易发现哪些IP下一定是有爬虫存在,而非正常用户的浏览器操作行为,从而达到检查到反爬、实施反爬行为的目的。

(4)精细化的反爬策略

 精细化体现在尽量不要误伤。因为现在大多数的上网行为多为NAT方式,对外只有一个IP,若针对IP直接反爬会造成大面积的误伤,对同在一个NAT下的其它用户会带来不便 ,尤其是像百度、新浪微博等这样的用户比较广的站点。

 实现的方式,其实也就是多个参数的组合,比如IP+UserAgent,Username+UserAgent、IP+UserName、或者是IP、Username加一些cookies中参数的组合匹配,像cookie_id等,这样可以减少被反爬影响的主机和用户范围。

四、爬虫设计之反爬设计

爬虫和反爬其实是矛与盾的关系,只要发现对方的破绽就可以了,百度和谷歌打击一些排名靠前的垃圾网站也是这样,总是有这样或那样的漏洞,只有发现后予以及时调整就好。爬虫和反爬也是如此。

(1)找到要爬的站点的反爬策略,以新浪微博为例

通过测试就可以发现新浪微博的反爬策略中一些参数,如是对username反爬、IP反爬、请求频率阈值等。在设计爬虫时,应该将这些参数设置为配置文件,或者是动态可自行调整,这个多为对自身程序设计的考验。如在自己设计天亮微博爬虫中,可以动态判定是否出现了反爬,如出现则进行用户提前切换或是直接切换代理等处理,尽最大程序保证爬虫的稳定健壮性。

(2) 爬虫设计的实现方法选择

 在第三步中的(3)中有介绍,爬虫很容易被识别的实现方式,如socket、httpurlconnection、httpclient等的实现,如果当确定服务器端的反爬很弱时,依然可以选择这些实现。如果发现很强时,则要选择phantomjs之类的实现。以我实测为例,微博爬虫完全可以选择httpclient等的实现,反爬策略已搞清,完全可以突破。但百度的就要采用phantomjs,因为它不对用户做限制,多以IP和操作相关做反爬设置,故选择之。

(3)反爬利器--IP代理服务器

    现在公认的反爬最有效的方式,即用代理,这个是谁都无法破解的。但前提是代价有点高,很多人负担不起。

IP代理有三种解决方案,1、网上找免费的,学习者可以一试。2、购买 IP代理服务,数据不够安全,你的所有请求都能被代理端拿到。3、自购服务器,搭建IP代理,这是代价高但最好的选择方式,现在我利青云公司的云主机,搭建了三台代理点,用其作代理去抓取各种百度、微博、电商等数据,效果非常好,这也是利器之所在。

 所以在爬虫设计时,一定要将代理服务及切换、容错等涉及在内,以提高以后的稳定性和扩展性。

五、小结

今天终于抽时间写了这篇共性问题的博文,写的比较随意,交流促进成长,共享成就未来。