【问题标题】:Designing a web crawler设计一个网络爬虫
【发布时间】:2011-08-15 15:25:29
【问题描述】:

我遇到了一个面试问题“如果您正在设计一个网络爬虫,您将如何避免陷入无限循环?”我正在尝试回答。

这一切是如何从头开始的。 假设谷歌从一些中心页面开始说数百个(首先如何找到这些中心页面是一个不同的子问题)。 当 Google 跟踪页面中的链接等时,它是否会不断制作一个哈希表以确保它不会跟踪之前访问过的页面。

如果同一个页面有 2 个名称 (URL) 会怎样?在我们有 URL 缩短器等的这些日子里说。

我以谷歌为例。虽然谷歌没有泄露它的网络爬虫算法和页面排名等是如何工作的,但有什么猜测吗?

【问题讨论】:

    标签: data-structures search-engine web-crawler google-search large-data-volumes


    【解决方案1】:

    网络爬虫是一种计算机程序,用于从给定的网站 URL 收集/爬取以下关键值(HREF 链接、图像链接、元数据等)。它被设计为智能跟踪已经从上一个 URL 中获取的不同 HREF 链接,因此,Crawler 可以从一个网站跳转到其他网站。通常,它被称为网络蜘蛛或网络机器人。这种机制始终充当 Web 搜索引擎的支柱。

    请从我的技术博客-http://www.algonuts.info/how-to-built-a-simple-web-crawler-in-php.html找到源代码

    <?php
    class webCrawler
    {
        public $siteURL;
        public $error;
    
        function __construct()
        {
            $this->siteURL = "";
            $this->error = "";
        }
    
        function parser()   
        {
            global $hrefTag,$hrefTagCountStart,$hrefTagCountFinal,$hrefTagLengthStart,$hrefTagLengthFinal,$hrefTagPointer;
            global $imgTag,$imgTagCountStart,$imgTagCountFinal,$imgTagLengthStart,$imgTagLengthFinal,$imgTagPointer;
            global $Url_Extensions,$Document_Extensions,$Image_Extensions,$crawlOptions;
    
            $dotCount = 0;
            $slashCount = 0;
            $singleSlashCount = 0;
            $doubleSlashCount = 0;
            $parentDirectoryCount = 0;
    
            $linkBuffer = array();
    
            if(($url = trim($this->siteURL)) != "")
            {
                $crawlURL = rtrim($url,"/");
                if(($directoryURL = dirname($crawlURL)) == "http:")
                {   $directoryURL = $crawlURL;  }
                $urlParser = preg_split("/\//",$crawlURL);
    
                //-- Curl Start --
                $curlObject = curl_init($crawlURL);
                curl_setopt_array($curlObject,$crawlOptions);
                $webPageContent = curl_exec($curlObject);
                $errorNumber = curl_errno($curlObject);
                curl_close($curlObject);
                //-- Curl End --
    
                if($errorNumber == 0)
                {
                    $webPageCounter = 0;
                    $webPageLength = strlen($webPageContent);
                    while($webPageCounter < $webPageLength)
                    {
                        $character = $webPageContent[$webPageCounter];
                        if($character == "")
                        {   
                            $webPageCounter++;  
                            continue;
                        }
                        $character = strtolower($character);
                        //-- Href Filter Start --
                        if($hrefTagPointer[$hrefTagLengthStart] == $character)
                        {
                            $hrefTagLengthStart++;
                            if($hrefTagLengthStart == $hrefTagLengthFinal)
                            {
                                $hrefTagCountStart++;
                                if($hrefTagCountStart == $hrefTagCountFinal)
                                {
                                    if($hrefURL != "")
                                    {
                                        if($parentDirectoryCount >= 1 || $singleSlashCount >= 1 || $doubleSlashCount >= 1)
                                        {
                                            if($doubleSlashCount >= 1)
                                            {   $hrefURL = "http://".$hrefURL;  }
                                            else if($parentDirectoryCount >= 1)
                                            {
                                                $tempData = 0;
                                                $tempString = "";
                                                $tempTotal = count($urlParser) - $parentDirectoryCount;
                                                while($tempData < $tempTotal)
                                                {
                                                    $tempString .= $urlParser[$tempData]."/";
                                                    $tempData++;
                                                }
                                                $hrefURL = $tempString."".$hrefURL;
                                            }
                                            else if($singleSlashCount >= 1)
                                            {   $hrefURL = $urlParser[0]."/".$urlParser[1]."/".$urlParser[2]."/".$hrefURL;  }
                                        }
                                        $host = "";
                                        $hrefURL = urldecode($hrefURL);
                                        $hrefURL = rtrim($hrefURL,"/");
                                        if(filter_var($hrefURL,FILTER_VALIDATE_URL) == true)
                                        {   
                                            $dump = parse_url($hrefURL);
                                            if(isset($dump["host"]))
                                            {   $host = trim(strtolower($dump["host"]));    }
                                        }
                                        else
                                        {
                                            $hrefURL = $directoryURL."/".$hrefURL;
                                            if(filter_var($hrefURL,FILTER_VALIDATE_URL) == true)
                                            {   
                                                $dump = parse_url($hrefURL);    
                                                if(isset($dump["host"]))
                                                {   $host = trim(strtolower($dump["host"]));    }
                                            }
                                        }
                                        if($host != "")
                                        {
                                            $extension = pathinfo($hrefURL,PATHINFO_EXTENSION);
                                            if($extension != "")
                                            {
                                                $tempBuffer ="";
                                                $extensionlength = strlen($extension);
                                                for($tempData = 0; $tempData < $extensionlength; $tempData++)
                                                {
                                                    if($extension[$tempData] != "?")
                                                    {   
                                                        $tempBuffer = $tempBuffer.$extension[$tempData];
                                                        continue;
                                                    }
                                                    else
                                                    {
                                                        $extension = trim($tempBuffer);
                                                        break;
                                                    }
                                                }
                                                if(in_array($extension,$Url_Extensions))
                                                {   $type = "domain";   }
                                                else if(in_array($extension,$Image_Extensions))
                                                {   $type = "image";    }
                                                else if(in_array($extension,$Document_Extensions))
                                                {   $type = "document"; }
                                                else
                                                {   $type = "unknown";  }
                                            }
                                            else
                                            {   $type = "domain";   }
    
                                            if($hrefURL != "")
                                            {
                                                if($type == "domain" && !in_array($hrefURL,$this->linkBuffer["domain"]))
                                                {   $this->linkBuffer["domain"][] = $hrefURL;   }
                                                if($type == "image" && !in_array($hrefURL,$this->linkBuffer["image"]))
                                                {   $this->linkBuffer["image"][] = $hrefURL;    }
                                                if($type == "document" && !in_array($hrefURL,$this->linkBuffer["document"]))
                                                {   $this->linkBuffer["document"][] = $hrefURL; }
                                                if($type == "unknown" && !in_array($hrefURL,$this->linkBuffer["unknown"]))
                                                {   $this->linkBuffer["unknown"][] = $hrefURL;  }
                                            }
                                        }
                                    }
                                    $hrefTagCountStart = 0;
                                }
                                if($hrefTagCountStart == 3)
                                {
                                    $hrefURL = "";
                                    $dotCount = 0;
                                    $slashCount = 0;
                                    $singleSlashCount = 0;
                                    $doubleSlashCount = 0;
                                    $parentDirectoryCount = 0;
                                    $webPageCounter++;
                                    while($webPageCounter < $webPageLength)
                                    {
                                        $character = $webPageContent[$webPageCounter];
                                        if($character == "")
                                        {   
                                            $webPageCounter++;  
                                            continue;
                                        }
                                        if($character == "\"" || $character == "'")
                                        {
                                            $webPageCounter++;
                                            while($webPageCounter < $webPageLength)
                                            {
                                                $character = $webPageContent[$webPageCounter];
                                                if($character == "")
                                                {   
                                                    $webPageCounter++;  
                                                    continue;
                                                }
                                                if($character == "\"" || $character == "'" || $character == "#")
                                                {   
                                                    $webPageCounter--;  
                                                    break;  
                                                }
                                                else if($hrefURL != "")
                                                {   $hrefURL .= $character; }
                                                else if($character == "." || $character == "/")
                                                {
                                                    if($character == ".")
                                                    {
                                                        $dotCount++;
                                                        $slashCount = 0;
                                                    }
                                                    else if($character == "/")
                                                    {
                                                        $slashCount++;
                                                        if($dotCount == 2 && $slashCount == 1)
                                                        $parentDirectoryCount++;
                                                        else if($dotCount == 0 && $slashCount == 1)
                                                        $singleSlashCount++;
                                                        else if($dotCount == 0 && $slashCount == 2)
                                                        $doubleSlashCount++;
                                                        $dotCount = 0;
                                                    }
                                                }
                                                else
                                                {   $hrefURL .= $character; }
                                                $webPageCounter++;
                                            }
                                            break;
                                        }
                                        $webPageCounter++;
                                    }
                                }
                                $hrefTagLengthStart = 0;
                                $hrefTagLengthFinal = strlen($hrefTag[$hrefTagCountStart]);
                                $hrefTagPointer =& $hrefTag[$hrefTagCountStart];
                            }
                        }
                        else
                        {   $hrefTagLengthStart = 0;    }
                        //-- Href Filter End --
                        //-- Image Filter Start --
                        if($imgTagPointer[$imgTagLengthStart] == $character)
                        {
                            $imgTagLengthStart++;
                            if($imgTagLengthStart == $imgTagLengthFinal)
                            {
                                $imgTagCountStart++;
                                if($imgTagCountStart == $imgTagCountFinal)
                                {
                                    if($imgURL != "")
                                    {
                                        if($parentDirectoryCount >= 1 || $singleSlashCount >= 1 || $doubleSlashCount >= 1)
                                        {
                                            if($doubleSlashCount >= 1)
                                            {   $imgURL = "http://".$imgURL;    }
                                            else if($parentDirectoryCount >= 1)
                                            {
                                                $tempData = 0;
                                                $tempString = "";
                                                $tempTotal = count($urlParser) - $parentDirectoryCount;
                                                while($tempData < $tempTotal)
                                                {
                                                    $tempString .= $urlParser[$tempData]."/";
                                                    $tempData++;
                                                }
                                                $imgURL = $tempString."".$imgURL;
                                            }
                                            else if($singleSlashCount >= 1)
                                            {   $imgURL = $urlParser[0]."/".$urlParser[1]."/".$urlParser[2]."/".$imgURL;    }
                                        }
                                        $host = "";
                                        $imgURL = urldecode($imgURL);
                                        $imgURL = rtrim($imgURL,"/");
                                        if(filter_var($imgURL,FILTER_VALIDATE_URL) == true)
                                        {   
                                            $dump = parse_url($imgURL); 
                                            $host = trim(strtolower($dump["host"]));
                                        }
                                        else
                                        {
                                            $imgURL = $directoryURL."/".$imgURL;
                                            if(filter_var($imgURL,FILTER_VALIDATE_URL) == true)
                                            {   
                                                $dump = parse_url($imgURL); 
                                                $host = trim(strtolower($dump["host"]));
                                            }   
                                        }
                                        if($host != "")
                                        {
                                            $extension = pathinfo($imgURL,PATHINFO_EXTENSION);
                                            if($extension != "")
                                            {
                                                $tempBuffer ="";
                                                $extensionlength = strlen($extension);
                                                for($tempData = 0; $tempData < $extensionlength; $tempData++)
                                                {
                                                    if($extension[$tempData] != "?")
                                                    {   
                                                        $tempBuffer = $tempBuffer.$extension[$tempData];
                                                        continue;
                                                    }
                                                    else
                                                    {
                                                        $extension = trim($tempBuffer);
                                                        break;
                                                    }
                                                }
                                                if(in_array($extension,$Url_Extensions))
                                                {   $type = "domain";   }
                                                else if(in_array($extension,$Image_Extensions))
                                                {   $type = "image";    }
                                                else if(in_array($extension,$Document_Extensions))
                                                {   $type = "document"; }
                                                else
                                                {   $type = "unknown";  }
                                            }
                                            else
                                            {   $type = "domain";   }
    
                                            if($imgURL != "")
                                            {
                                                if($type == "domain" && !in_array($imgURL,$this->linkBuffer["domain"]))
                                                {   $this->linkBuffer["domain"][] = $imgURL;    }
                                                if($type == "image" && !in_array($imgURL,$this->linkBuffer["image"]))
                                                {   $this->linkBuffer["image"][] = $imgURL; }
                                                if($type == "document" && !in_array($imgURL,$this->linkBuffer["document"]))
                                                {   $this->linkBuffer["document"][] = $imgURL;  }
                                                if($type == "unknown" && !in_array($imgURL,$this->linkBuffer["unknown"]))
                                                {   $this->linkBuffer["unknown"][] = $imgURL;   }
                                            }
                                        }
                                    }
                                    $imgTagCountStart = 0;
                                }
                                if($imgTagCountStart == 3)
                                {
                                    $imgURL = "";
                                    $dotCount = 0;
                                    $slashCount = 0;
                                    $singleSlashCount = 0;
                                    $doubleSlashCount = 0;
                                    $parentDirectoryCount = 0;
                                    $webPageCounter++;
                                    while($webPageCounter < $webPageLength)
                                    {
                                        $character = $webPageContent[$webPageCounter];
                                        if($character == "")
                                        {   
                                            $webPageCounter++;  
                                            continue;
                                        }
                                        if($character == "\"" || $character == "'")
                                        {
                                            $webPageCounter++;
                                            while($webPageCounter < $webPageLength)
                                            {
                                                $character = $webPageContent[$webPageCounter];
                                                if($character == "")
                                                {   
                                                    $webPageCounter++;  
                                                    continue;
                                                }
                                                if($character == "\"" || $character == "'" || $character == "#")
                                                {   
                                                    $webPageCounter--;  
                                                    break;  
                                                }
                                                else if($imgURL != "")
                                                {   $imgURL .= $character;  }
                                                else if($character == "." || $character == "/")
                                                {
                                                    if($character == ".")
                                                    {
                                                        $dotCount++;
                                                        $slashCount = 0;
                                                    }
                                                    else if($character == "/")
                                                    {
                                                        $slashCount++;
                                                        if($dotCount == 2 && $slashCount == 1)
                                                        $parentDirectoryCount++;
                                                        else if($dotCount == 0 && $slashCount == 1)
                                                        $singleSlashCount++;
                                                        else if($dotCount == 0 && $slashCount == 2)
                                                        $doubleSlashCount++;
                                                        $dotCount = 0;
                                                    }
                                                }
                                                else
                                                {   $imgURL .= $character;  }
                                                $webPageCounter++;
                                            }
                                            break;
                                        }
                                        $webPageCounter++;
                                    }
                                }
                                $imgTagLengthStart = 0;
                                $imgTagLengthFinal = strlen($imgTag[$imgTagCountStart]);
                                $imgTagPointer =& $imgTag[$imgTagCountStart];
                            }
                        }
                        else
                        {   $imgTagLengthStart = 0; }
                        //-- Image Filter End --
                        $webPageCounter++;
                    }
                }
                else
                {   $this->error = "Unable to proceed, permission denied";  }
            }
            else
            {   $this->error = "Please enter url";  }
    
            if($this->error != "")
            {   $this->linkBuffer["error"] = $this->error;  }
    
            return $this->linkBuffer;
        }   
    }
    ?>
    

    【讨论】:

    • 这并没有真正回答这个问题:“如果你正在设计一个网络爬虫,你将如何避免陷入无限循环?”请改进你的答案。
    • 你好大脑先生,感谢cmets,实际上我们需要为这个类创建一个实例,然后我们才能申请使用。
    【解决方案2】:

    如果您想获得详细答案,请查看section 3.8 this paper,它描述了现代抓取工具的 URL-seen 测试:

    在提取链接的过程中,任何 网络爬虫会遇到多个 指向同一文档的链接。避免 下载和处理文档 多次,URL-seen 测试必须 在每个提取的链接上执行 在将其添加到 URL 边界之前。 (另一种设计是 而是在以下情况下执行 URL-seen 测试 该 URL 已从边界中删除, 但这种方法会导致 更大的边界。)

    执行 URL-seen 测试,我们存储所有 墨卡托在规范中看到的 URL 在称为 URL 的大表中形成 放。再次,条目太多 让他们都适合记忆,所以喜欢 文档指纹集,URL set 主要存储在磁盘上。

    保存 空间,我们不存储文本 URL 中每个 URL 的表示 设置,而是一个固定大小的 校验和。不同于指纹 提交给内容可见测试 文档指纹集,流 针对 URL 集测试的 URL 有 大量的局部性。到 减少操作次数 支持磁盘文件,因此我们保留 流行 URL 的内存缓存。 这个缓存的直觉是 一些 URL 的链接很常见, 所以将流行的缓存在内存中 将导致高内存命中 率。

    事实上,使用内存 缓存 2^18 个条目和类似 LRU 时钟更换政策,我们实现 内存中的总体命中率 缓存66.2%,命中率9.5% 在最近添加的 URL 表上, 净命中率为75.7%。而且, 在 24.3% 的请求中丢失 流行 URL 的缓存和 最近添加的 URL 表,关于 1=3 在我们的缓冲区中产生命中 随机访问文件实现, 它也驻留在用户空间中。这 所有这些缓冲的最终结果是 我们执行的每个成员资格测试 在 URL 集上的结果是平均的 0.16 seek 和 0.17 read kernel 调用(其中一部分是 从内核的文件系统中提供 缓冲区)。因此,每个 URL 集成员资格 测试诱导六分之一的内核 调用作为成员资格测试 文档指纹集。这些 节省纯粹是由于金额 URL 局部性(即重复 流行的 URL)流中固有的 抓取期间遇到的 URL。

    基本上,它们使用哈希函数对所有 URL 进行哈希处理,该哈希函数保证每个 URL 的唯一哈希值,并且由于 URL 的局部性,查找 URL 变得非常容易。谷歌甚至开源了他们的哈希函数:CityHash

    警告!
    他们也可能在谈论机器人陷阱!!!机器人陷阱是页面的一部分,它不断生成具有唯一 URL 的新链接,通过跟踪该页面提供的链接,您基本上会陷入“无限循环”。这并不完全是一个循环,因为循环会是访问同一个 URL 的结果,但它是一个无限的 URL 链,您应该避免抓取。

    2012 年 12 月 13 日更新- 世界应该结束的第二天 :)

    根据 Fr0zenFyr 的评论:如果使用AOPIC 算法来选择页面,那么避免无限循环类型的机器人陷阱相当容易。以下是 AOPIC 工作原理的摘要:

    1. 获取一组 N 个种子页面。
    2. 为每个页面分配 X 数量的信用,以便在开始抓取之前每个页面都有 X/N 信用(即相等数量的信用)。
    3. 选择一个页面 P,其中 P 的信用额度最高(或者如果所有网页的信用额度都相同,则抓取一个随机网页)。
    4. 抓取页面 P(假设抓取时 P 有 100 个积分)。
    5. 从页面 P 中提取所有链接(假设有 10 个)。
    6. 将 P 的信用设置为 0。
    7. 收取 10% 的“税”并将其分配给 Lambda 页面。
    8. 从 P 的原始信用 - 税收中为页面 P 上的每个链接分配等量的信用:因此(100(P 信用)-10(10% 税))/10(链接)=每个链接 9 信用。
    9. 从第 3 步开始重复。

    由于 Lambda 页面不断地收税,最终它会成为信用额度最大的页面,我们将不得不“抓取”它。我用引号说“抓取”,因为我们实际上并没有对 Lambda 页面发出 HTTP 请求,我们只是将其功劳分配给我们数据库中的所有页面。 p>

    由于机器人陷阱只提供内部链接信用并且它们很少从外部获得信用,它们会不断地将信用(来自税收)泄漏到 Lambda 页面。 Lambda 页面会将积分平均分配给数据库中的所有页面,并且在每个循环中,机器人陷阱页面将失去越来越多的积分,直到它的积分太少以至于几乎不再被抓取。好的页面不会发生这种情况,因为它们经常从其他页面上的反向链接中获得积分。这也会导致动态页面排名,您会注意到,每当您拍摄数据库快照时,按照页面的信用量对页面进行排序,然后很可能会根据它们的 大致排序真实的页面排名

    这只能避免无限循环类型的机器人陷阱,但您应该注意many other bot traps,也有办法绕过它们。

    【讨论】:

    • 很好的解释。我对循环(上面已经回答)和机器人陷阱(仍在寻找一种很好的绕过方式)有同样的问题。如果允许的话,我会为 CityHash 额外 +1。干杯;)
    • @Fr0zenFyr 您不必担心无限循环类型的机器人陷阱,特别是如果您使用AOPIC 算法来选择要抓取的 URL。我会更详细地更新我的答案。
    • @Fr0zenFyr 因此,避免机器人陷阱的最佳方法是礼貌地爬行,否则您将不得不查看all the ways you can get trapped 并解决它们。 IE。你基本上必须实现一个浏览器,使用代理,并通过切换用户代理来模拟多个浏览器(按照browser usage statistics
    • 我当前的模型完全遵循 robots.txt、no-follow 等,并且不会进行激进的抓取。感谢您更新您的帖子,我会尝试您对 AOPIC 的建议。顺便说一句,玛雅历法审判日是 21Dec2012 [翻白眼].. ;)
    • @raju 不会在每个周期都发生,它只会在您“抓取”lambda 时发生。 “爬行” lambda 不应该经常发生,您可以异步进行。它不需要实时发生,它只需要最终发生。
    【解决方案3】:

    这是一个网络爬虫示例。可以用来收集mac地址进行mac欺骗。

    #!/usr/bin/env python
    
    import sys
    import os
    import urlparse
    import urllib
    from bs4 import BeautifulSoup
    
    def mac_addr_str(f_data):
    global fptr
    global mac_list
    word_array = f_data.split(" ")
    
        for word in word_array:
            if len(word) == 17 and ':' in word[2] and ':' in word[5] and ':' in word[8] and ':' in word[11] and ':' in word[14]:
                if word not in mac_list:
                    mac_list.append(word)
                    fptr.writelines(word +"\n")
                    print word
    
    
    
    url = "http://stackoverflow.com/questions/tagged/mac-address"
    
    url_list = [url]
    visited = [url]
    pwd = os.getcwd();
    pwd = pwd + "/internet_mac.txt";
    
    fptr = open(pwd, "a")
    mac_list = []
    
    while len(url_list) > 0:
        try:
            htmltext = urllib.urlopen(url_list[0]).read()
        except:
            url_list[0]
        mac_addr_str(htmltext)
        soup = BeautifulSoup(htmltext)
        url_list.pop(0)
        for tag in soup.findAll('a',href=True):
            tag['href'] = urlparse.urljoin(url,tag['href'])
            if url in tag['href'] and tag['href'] not in visited:
                url_list.append(tag['href'])
                visited.append(tag['href'])
    

    更改网址以抓取更多网站......祝你好运

    【讨论】:

      【解决方案4】:

      虽然这里的每个人都已经建议了如何创建您的网络爬虫,但下面是 Google 如何对页面进行排名的方式。

      Google 根据回调链接的数量(其他网站上有多少链接指向特定网站/页面)为每个页面提供排名。这称为相关性分数。这是基于这样一个事实:如果一个页面有许多其他页面链接到它,那么它可能是一个重要页面。

      每个站点/页面都被视为图表中的一个节点。到其他页面的链接是有向边。顶点的度数定义为传入边的数量。传入边数较多的节点排名较高。

      PageRank 的确定方法如下。假设页面 Pj 有 Lj 个链接。如果其中一个链接指向页面 Pi,则 Pj 会将其重要性的 1/Lj 传递给 Pi。 Pi 的重要性排名是链接到它的页面所做的所有贡献的总和。因此,如果我们用 Bi 表示链接到 Pi 的页面集,那么我们就有这个公式:

      Importance(Pi)= sum( Importance(Pj)/Lj ) for all links from Pi to Bi
      

      排名被放置在一个称为超链接矩阵的矩阵中:H[i,j]

      如果存在从 Pi 到 Bi 的链接,则此矩阵中的一行为 0 或 1/Lj。这个矩阵的另一个特性是,如果我们将一列中的所有行相加,我们得到 1。

      现在我们需要将该矩阵乘以一个特征向量,命名为 I(特征值为 1),这样:

      I = H*I
      

      现在我们开始迭代:IH, IIH, IIIH .... I^k *H 直到解决方案收敛。即我们在第 k 步和第 k+1 步中得到的矩阵中的数字几乎相同。

      现在 I 向量中剩下的就是每个页面的重要性。

      有关简单的课堂作业示例,请参阅http://www.math.cornell.edu/~mec/Winter2009/RalucaRemus/Lecture3/lecture3.html

      至于解决面试问题中的重复问题,请在整个页面上进行校验和,并使用该校验和或校验和的 bash 作为地图中的键来跟踪访问过的页面。

      【讨论】:

      • 如果页面吐出动态内容,校验和可能会有所不同。
      • @edocetirwi 好点,我想你必须寻找其他东西或以某种有意义的方式将它与 URL 结合起来
      • 哦,所以你只需整合hyperlink matrix,其尺寸为every-webpage-on-the-internet x every-webpage-on-the-internet。简单?!?一个人是如何做到这一点的(考虑到它是一个 very 稀疏矩阵)?
      • @CpILL 你迟到了 7 年,但是有一些聪明的方法可以在不爆炸的情况下将大矩阵相乘;如果您想要生产就绪的解决方案,我愿意接受付款
      • @Adrian 我确定你是......但我注意到它主要是 Stackoverflow 上的开发人员,我们喜欢自己做,这就是我们在这里的原因! :D
      【解决方案5】:

      这里的问题是不抓取重复的 URL,这是通过使用从 url 获得的哈希的索引来解决的。问题是抓取重复的内容。 “Crawler Trap”的每个 url 都是不同的(年、日、SessionID...)。

      没有“完美”的解决方案……但您可以使用其中的一些策略:

      • 保留网址在网站内的最高级别的字段。对于从页面获取 url 的每个 cicle,增加级别。它会像一棵树。您可以在某个级别停止爬行,例如 10 级(我认为谷歌使用这个)。

      • 您可以尝试创建一种可以比较的 HASH 以找到相似的文档,因为您无法与数据库中的每个文档进行比较。谷歌有 SimHash,但我找不到任何可以使用的实现。然后我创建了我自己的。我的哈希计算 html 代码中的低频和高频字符,并生成一个 20 字节的哈希,与 AVLTree 中最后一次爬网页面的小缓存进行比较,并带有一定容差的 NearNeighbors 搜索(大约 2)。您不能在此哈希中使用对字符位置的任何引用。在“识别”陷阱后,您可以记录重复内容的 url 模式并开始忽略具有该模式的页面。

      • 与 google 一样,您可以为每个网站创建一个排名,并比其他网站更“信任”一个。

      【讨论】:

        【解决方案6】:

        取决于他们的问题的深度。如果他们只是想避免来回跟踪相同的链接,那么散列 URL 就足够了。

        如果内容具有数以千计的指向相同内容的 URL,该怎么办?就像 QueryString 参数一样,它不会影响任何东西,但可以进行无限次迭代。我想您也可以对页面内容进行哈希处理并比较 URL 以查看它们是否类似于捕获由多个 URL 标识的内容。例如,请参阅@Lirik 的帖子中提到的 Bot Traps。

        【讨论】:

        • 这让我想到了另一个问题。我们如何散列页面的全部内容。这样的页面至少有 2 个寻呼机。什么样的散列函数能够将 2 个寻呼机散列为一个值?通常这样的哈希输出的大小是多少?
        【解决方案7】:

        好吧,网络基本上是一个有向图,因此您可以从 url 构建一个图,然后在标记访问过的节点的同时进行 BFS 或 DFS 遍历,这样您就不会两次访问同一页面。

        【讨论】:

        • 但是首先你是如何构建图表的呢?如果我们不想要重复的节点,即我们只想要一个 url 的节点,那么您需要一种方法来在构建图形本身时检测和丢弃重复..
        • @learnerforever 嗯嗯,没错……老实说,我只写了一个简单的爬虫,它只处理大约 100 个链接,所以实际上进入每个页面并不是一个大问题。但是是的,当您将其应用于整个网络时,我可以看到出现的问题。不过,Lirik 的论文似乎很有价值……
        【解决方案8】:

        你必须有某种哈希表来存储结果,你只需要在每个页面加载之前检查它。

        【讨论】:

          猜你喜欢
          • 2016-05-08
          • 2012-04-18
          • 1970-01-01
          • 2011-12-11
          • 1970-01-01
          • 1970-01-01
          • 2021-05-26
          • 2014-01-01
          • 1970-01-01
          相关资源
          最近更新 更多