在抓取时管理网址的常用方法是什么?

时间:2011-12-28 21:09:03

标签: web-crawler

我正在尝试编写一个网络爬虫程序,但现在我想知道:存储所有网址的最佳方法是什么,以便抓取工具可以一起工作但不会干扰?

示例:

  • Crawler 1找到包含100个网址的网页<​​/ li>
  • 抓取工具2找到没有任何网址的网页<​​/ li>
  • 抓取工具1和2将分享 Crawler 1找到的100个网址

我的想法(两种不同的方法)

  1. Crawler扫描页面以获取新网址
    • 将所有找到的网址保存在由Queue
    • 的所有实例共享的Crawler(PriorityQueue)中
    • 一旦Queue变得太大(例如最大尺寸的80%),就会将网址外包给数据库
  2. Crawler稍后保存HTML并Analyzer搜索网址
    • 将新网址保存到水平缩放数据库
    • 始终向此数据库询问下一个网址
  3. 问题

    1. 共享的Queue是瓶颈吗?
    2. 如果数据库最终只是一致的话,如何阻止多个抓取工具获取相同的URL两次?
    3. 其他解决方案?

      还有其他解决方案吗?什么是网络爬虫的标准解决方案?

2 个答案:

答案 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请求感到不安。