网络爬虫
通用爬虫技术框架
爬虫系统首先从互联网页面中精心选择一部分网页,以这些网页的链接地址作为种子URL,将这些种子放入待爬取URL队列中,爬虫从待爬取URL队列依次读取,并将URL通过DNS解析,把链接地址转换为网站服务器对应的IP地址。然后将其和网页相对路径名交给网页下载器,网页下载器负责页面的下载。对于下载到本地的页面,一方面将其存储到页面库中,等待建立索引等后续处理;另一方面将下载页面的URL放入已抓取队列中这个队列记录了爬虫系统已经下载过的网页URL,以避免系统的重复抓取。对于刚下载的网页,从中抽取出包含的所有连接信息,并在已下载的URL队列中进行检查,如果发现链接还没有抓取过,则放到待抓取URL队列的末尾,在之后的抓取调度中会下载这个URL对应的网页。如此这般,形成循环,直到待抓取URL队列为空,这代表着爬虫系统将能够抓取的网页已经悉数抓完,此时完成了一轮完整的抓取过程。
上述是一个通用爬虫的整体流程,如果从更加宏观的角度考虑,处于动态抓取过程中的爬虫和互联网所有网页之间的关系,可以概括为以下5个部分:
已下载网页集合:爬虫已经从互联网下载到本地进行索引的网页集合。
已过期网页集合:由于网页数量庞大,爬虫完整爬取一轮需要较长时间,在抓取过程中,很多已下载的网页可能已经更新了,从而导致过期。之所以如此,是因为互联网网页处于不断的动态变化过程中,所以易产生本地网页内容和真实互联网不一致的情况。
待下载网页集合:处于待抓取URL队列中的网页,这些网页即将被爬虫下载。
未知网页集合:有些网页对于爬虫是无法抓取到的,这部分网页构成了未知网页集合。事情是,这部分网页所占的比例很高。
从理解爬虫的角度看,对互联网网页给出如上划分有助于深入理解搜索引擎爬虫所面临的主要任务和挑战。绝大多数爬虫系统遵循上文的流程,但是并非所有的爬虫系统都如此一致。根据具体应用的不同,爬虫系统在许多方面存在差异,大体而已,可以将爬虫系统分为如下3种类型。
批量型爬虫:批量型爬虫有比较明确的抓取范围和目标,当爬虫达到这个设定的目标后,即停止抓取过程。至于具体目标可能各异,也许是设定抓取一定数量的网页即可,也许是设定抓取的时间等,各不一样。
增量型爬虫:增量型爬虫与批量型爬虫不同,会保持持续不断的抓取,对于抓取到的网页,要定期更新,因为互联网网页处于不断变化中,新增网页、网页被删除或者网页内容更改都很常见,而增量型爬虫需要及时反映这种变化,所以处于持续不断的抓取过程中,不是在抓取新网页,就是在更新已有网页。通用的商业搜索引擎爬虫基本都属此类。
垂直型爬虫:垂直型爬虫关注特定主题内容或者属于特定行业的网页,比如对于健康网站来说,只需要从互联网页面里找到与健康相关的页面内容即可,其他行业的内容不在考虑范围。垂直型爬虫一个最大的特点和难点就是:如何识别网页内容是否属于指定行业或主题。从节省系统资源的角度来讲,不可能把所有互联网页面下载之后在进行筛选,这样会造成资源过度浪费,往往需要爬虫在抓取阶段就能够动态识别某个网址是否与主题相关,并尽量不去抓取无关页面,以达到节省资源的目的。垂直搜索网站或者垂直行业网站往往需要此种类型的爬虫。
页面爬行策略
深度优先策略
深度优化策略即一条道走到黑,当沿着一个路径走到无路可走时,再返回来走另一条路。如图为深度优先抓取策略的示意图,假设A页面为Spider的入口,Spider在A页面上发现了1、7、11三个页面的链接,然后Spider会按照图中数字所表示的顺序依次进行抓取。当第一条路径抓到3页面时到头了,然后返回2页面抓取第二条路径中的4页面,在4页面也抓到头了,就会返回1页面抓取第三条路径中的5页面,并顺着一路抓下去,抓到头后会按照之前的规则沿一条一条路径抓下去。
广度优先策略
广度优先策略即Spider在一个页面上发现多个链接时,并不是一条路走到黑,顺着一个链继续抓下去,而是先把这些页面抓一遍,然后再抓从这些页面中提取下来的链接。如图所示为广度优先抓取策略的示意图。假设A页面为Spider的入口,Spider在A页面上发现了1、2、3三个页面。当抓完1网页时,只是把1网页中4和5的网页的链接放入待抓取URL列表,并不会抓取1页面中的其他链接,而是抓2页面。当b级页面抓取完成之时,才会抓取从b级页面中提取到c级页面中的4、5、6、7、8、9六个页面,等c级页面抓取完成后,再抓取从c页面中提取到的d级新页面,依次持续抓取下去。
网页选择策略
网页选择策略也称为"页面选择问题"(page Selection),通常是尽可能地首先抓取重要性的网页,这样保证在有限的资源内尽可能地照顾到那些重要性高的网页。重要性度量由链接欢迎度、链接重要度和平均链接深度这个方面决定。定义链接欢迎度为IB(P),它主要由反向链接(Backinks)的数目和质量决定。首先考察数目,直观地讲,一个网页有越多的链接指向它(反向链接数多),那么表示其他网页对其的认可。同时这个网页被网民访问的机会就大,推测出其重要性也就越高;其次考察质量,如果被越多的重要性高的网指向,那么其重要性也就越高。如果不考虑质量,就会出现局部最优,而不是全局最优的问题。最典型的就是作弊网页,人为地在一些网页中设置了大量反策链接指向其自身的网页,以提高该网页的重要性。如果不考虑链接质量,就会被这些作弊者所利用。
重访策略
重访策略是搜索引擎蜘蛛在抓取完这个网页之后,然后根据这个页面的权重、包括它的更新频率、更新质量、外链的数量等等来判定,那么对于权重高的页面,蜘蛛会在相隔较短的时间段在回来重新抓取,比如新浪网,权重很高,搜索引擎蜘蛛都是按照秒来重新抓取的。而对于一些权重较低的页面,比如长期不更新的页面,那么蜘蛛会隔好长时间在来抓取一次,比如我们常常搜索的百度大更新,蜘蛛就是对于一些网页权重较低的页面进行一次全部的抓取,一般情况,百度大更新,一个月一次。
URL消重
将URL保存到数据库进行去重
为了尽快把整个爬虫搭建起来,最开始的URL去重采用方案是直接利用数据库的唯一约束进行去重,这是最省时的做法,所有人都能想得到和做到。
将URL放到HashSet中去重
在数据库中去重,每次比较都有一次请求数据库的过程,这里对数据库的性能消耗是很大的。于是可以使用将URL放到内存中的HashSet中去重,HashSet中放置的就是URL的字符串,任何一个新的URL首先在HashSet中进行查找,如果HashSet中没有,就将新的URL插入HashSet,并将URL放入待抓取队列。这个方案的好处是它的去重效果精确,不会漏过一个重复的URL。它的缺点是,随着数据的增加会出现Out Of Memory。假设单个URL的平均长度是100 byte,那么一亿条数据占用10G内存,大部分的电脑内存在4G和8G,那么留给JVM的内存就更少啦,那么出现内存泄漏是迟早的事。
将URL经过MD5之后保存到HashSet
这里的处理方式就是HashSet中不存储原始的URL,而是将URL压缩后再放进去。压缩的方式有很大,用MD5对URL做编码是比较省时的一种方式。 MD5的结果是128 bit也就是16 byte的长度,相比于之间估计的URL平均长度100byte已经缩小了6倍多,一亿条数据占用1.6G的内存,Scrapy采用的就是类似方法。当然,不管使用那种压缩算法,随着URL越来越多,终有一天还是会Out Of Memory。所以,这个方案不解决本质问题。 MD5另外一个问题是,有可能两个相同的URL被映射成同一个MD5值,这样的话,它们中有一个就永远不会被抓取了。
使用Bitmap方法去重
使用Bitmap方法去重的原理是把URL经过hash后映射到bit的每一个位上,一亿URL占用约12M,主要缺点是去重没那么精准,存在冲突。
布隆过滤器(Bloom Filter)
Boolm Filter是一个m位的位数组,且数组被0所填充。同时,我们需要定义k个不同的hash函数,每一个hash函数都随机的将每一个输入元素映射到位数组中的一个位上。那么对于一个确定的输入,我们会得到k个索引。
插入元素:经过k个hash函数的映射,我们会得到k个索引,我们把位数组中这k个位置全部置1(不管其中的位之前是0还是1)
查询元素:输入元素经过k个hash函数的映射会得到k个索引,如果位数组中这k个索引任意一处是0,那么就说明这个元素不在集合之中;如果元素处于集合之中,那么当插入元素的时候这k个位都是1。但如果这k个索引处的位都是1,被查询的元素就一定在集合之中吗?答案是不一定,也就是说出现了False Positive的情况(但Bloom Filter不会出现False Negative的情况)
在上图中,当插入x、y、z这三个元素之后,再来查询w,会发现w不在集合之中,而如果w经过三个hash函数计算得出的结果所得索引处的位全是1,那么Bloom Filter就会告诉你,w在集合之中,实际上这里是误报,w并不在集合之中。
反爬虫机制
IP封锁
常见网站反爬虫首先考虑到会不会对用户产生误伤,举个例子,在校园网内,有台机器对网站持续高频繁产生请求,校园网涉及用户过多,但是如果封锁IP那么会对校园中的用户产生误伤,丧失了许多用户量,就拿某宝那么大的公司来说,不到万不得已时,不会对IP进行长时间或者进行封锁。
解决方案:
1.采用修改程序访问频率
可以休息两秒例如time.sleep(2)
2.采用IP代理的方式,进行对网站数据量的爬取
#导入requests库,如果使用其他的自行导入import requests
proxies = { http: http://127.0.0.1:8888, https: http://127.0.0.11:1080,}
requests.get(url, proxies=proxies)
协议头
绝大多数网站,访问时会判断来源,例如手机用户和电脑用户同样访问QQ空间,但是页面却是不一样的,这个为什么呢?,在写爬虫中网站也判断其来源,爬虫初学者在初学的时候会写出这样的代码
举个栗子
rs= requests.get('http://baidu.com')print(rs.text)
相信这段代码很多初学者都使用过,百度这种搜索引擎网站页面是不会管是不是爬虫或者是其他的人在访问,再举个栗子
rs=requests.get('http://jianshu.com')
返回状态为 response404
这是为什么呢,简书判断不到用户的访问来源,所以会返回一个404错误来告知,你是一个爬虫,拒绝访问。
那么如何解决呢
解决方案
headers = {'User-Agent':'Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36}
rs=requests.get('http://jianshu.com')
返回状态为response200
这时我们可以愉快地访问了。
验证码
当用户请求频率过高的时候,有些网站就会触发验证码验证机制,让你输入各种验证码 常用的举个栗子,12306购票时,客户多次请求网站的查询票的请求,在购买车票的的时候,会显现出验证码,那么12306判断你是否是机器人,
解决方案
加入打码平台
需要登录才能获得信息
例如知乎,FaceBook ...等网站需要用户登录之后才能够获取页面中的信息,那么这种防护能非常有效的防止数据大批量的被爬取。
解决方案:
1.小数据量(模拟登录后再去爬取,或者使用cookies 直接进行爬取)
2.申请诸多的账号去养这些号,然后登录,或者获得cookies进行爬取。
js图片类的反爬
例如爬虫在爬取网站的时候,会获取主页中的有效信息,但是对于他不需要的,爬虫不进行访问,而在真实用户用浏览器访问的时候会访问到主页上的js和图片资源,那么服务器端,就会判断该用户下是否访问了这些资源来判断是否爬虫。
解决方案
使用selenium
Selenium是一个用于Web应用程序测试的工具。Selenium测试直接运行在浏览器中,就像真正的用户在操作一样。支持的浏览器包括IE(7, 8, 9, 10, 11),Mozilla Firefox,Safari,Google Chrome,Opera等。
WebCollector爬虫框架
WebCollector 是一个无须配置、便于二次开发的 Java 爬虫框架(内核),它提供精简的的 API,只需少量代码即可实现一个功能强大的爬虫。WebCollector-Hadoop 是 WebCollector 的 Hadoop 版本,支持分布式爬取。