当我们通过A网页提取出B网页的URL对B网页进行爬取,而B网页又包含了A网页的URL(这种情况很常见,例如很多网页都会有返回首页的链接,点击就会返回首页)此时没有经过良好设计的爬虫就可能通过B网页提取出A网页的链接再次对A网页进行爬取。这样爬虫就会把所有时间都花在获取大量相同的页面上,不停的兜圈子,进入了死循环,死循环会给网站的服务器造成负担,并消耗网络带宽。
爬取过的URL添加进列表来记录已经爬取过的网页把,在爬取一个网页时把网页的URL和这个列表进行对比来确认是否爬取过这个页面(有损的存在位图可以减少列表数据的占用空间,树和散列表可以加快查找对比的速度,都是可以发挥作用的数据结构此时,但这里不多做讨论),列表中存在这个URL时成熟的爬虫应该拒绝爬行这个网页,这样能避免陷入死循环,这种方案大型爬虫产品中几乎是必须的在。
但我们知道URL是有别名的,看似不同的URL可能会指向资源和结构都相同的同一网页,这会给URL的对比造成麻烦,以下展示四个案列来介绍常见别名形式。
1.https://scrapy.org与https://scrapy.org:80
HTTP协议的默认端口就是80端口,即使不特别声明也将使用80端口来和服务器通讯。所以遇见没有声明端口的URL我们应该向主机名后面追加默认的80端口后再添加进列表。
2.http:/www.foo.com/readme.htm与http:/www.foo.com/README.HTM
因为服务器是大小写不敏感的,所以这两个URL等价。这里爬虫需要知道服务器是否大小写不敏感才能避免这种问题。
3.http://opinion.people.com.cn/GB/223228/index.html与http://127.0.0.1/GB/223228/index.html(这里的IP用环回地址代替,不是实例,了解逻辑即可)
这里的opinion.people.com.cn就表示服务器IP的主机名(别名),真实IP和主机名都指向同一计算机,opinion.people.com.cn可以被服务器真实IP代替所以。/GB/223228/index.html则表示客户端请求此服务器的资源所在目录。
4.https://scrapy.org#spider与.https://scrapy.org#crawler
#标签并不会改变页面内容,所以它们等价。我们应该删除#标签再添加进列表。
除了以上这些URL别名问题以外,还有重定向网页等需要爬虫多加注意,稍有不慎就会掉入死循环的陷阱。