我正在尝试编写一个网络爬虫程序,但现在我想知道:存储所有网址的最佳方法是什么,以便抓取工具可以一起工作但不会干扰?
示例:
我的想法(两种不同的方法)
Crawler
扫描页面以获取新网址
Queue
Crawler
(PriorityQueue)中
Queue
变得太大(例如最大尺寸的80%),就会将网址外包给数据库Crawler
稍后保存HTML并Analyzer
搜索网址
问题
Queue
是瓶颈吗?其他解决方案?
还有其他解决方案吗?什么是网络爬虫的标准解决方案?
答案 0 :(得分:3)
[虽然这是一个老问题,我为了搜索到这里的搜索者添加了这个答案]
您要找的是Bloom Filter。
虽然大多数开源Bloom过滤器都是专为本地访问而设计的库,但实际上将它们转换为Web服务并因此成为多个节点的共享资源实际上是微不足道的。
这是将php-bloom-filter与静态缓存库一起使用的一个非常基本的示例:
<?php
// assumes $_POST contains a JSON-encoded array of URLs to check ($links)
// and a unique crawl identifier ($crawl_id)
extract($_POST);
if (!$b = unserialize(Cache::read('filter_'.$crawl_id))) {
$b = new BloomFilter(100000, 0.001);
}
$return = array();
foreach (json_decode($links, true) as $link) {
if (!$b->has($crawl_id.'_'.$link)) {
$return[] = $link;
$b->add($crawl_id.'_'.$link);
}
}
// put the filter back into our cache
Cache::write('filter_'.$crawl_id, serialize($b));
echo json_encode($return);
然后,任何使用Bloys过滤器检查的URL都会被推送到您的抓取队列中,以便您的抓取节点进行抓取。
这种实现显然不是针对网络规模的抓取而设计的,但对于高达100k或更多页面的单个网站抓取(取决于您的可用服务器资源)可能会很好。当然,如果你确实需要使用bloom过滤器来水平扩展,那么你可以在代理后面使用多个bloom节点,所有节点都使用某些描述的分布式缓存(redis / memcache / ehcache等)。你需要在缓存对象之间进行一些巧妙的分片以保持查找速度,但我确信你会在需要的时候解决这个问题。
上面唯一的警告是,您偶尔会得到一个误报并最终多次抓取同一个网址 - 这是大多数网络抓取工具的事实,所以这只是您应该在抓取解析时优雅处理的情况代码。
答案 1 :(得分:0)
你有一个以上的问题,但对于一种通用的方法,这是怎么回事。
有关确定两个网址是否相同的信息,请参阅此SO discussion。
然后,你真的有很多选择。我个人最喜欢的是写三件事。
1)仅处理等待访问的URL列表的数据库应用程序
2)存储来自访问站点的重要结果的数据库应用程序。无论你想保存什么。
3)可以查询并发布到(1)然后发布到(2)
为什么这样?
您可以将(1)和(2)放在一台机器上。 (3)可以从任何地方运行,允许您从多个IP地址运行多个实例。这将帮助您导航服务提供商和其他网络人员,他们可能会对您重复和频繁的http请求感到不安。