设计一个网络爬虫

Posted

技术标签:

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

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

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

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

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

【问题讨论】:

【参考方案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 工作原理的摘要:

    获取一组 N 个种子页面。 为每个页面分配 X 数量的信用,以便在开始抓取之前每个页面都有 X/N 信用(即相等数量的信用)。 选择一个页面 P,其中 P 的信用额度最高(或者如果所有网页的信用额度都相同,则抓取一个随机网页)。 抓取页面 P(假设抓取时 P 有 100 个积分)。 从页面 P 中提取所有链接(假设有 10 个)。 将 P 的信用设置为 0。 收取 10% 的“税”并将其分配给 Lambda 页面。 从 P 的原始信用 - 税收中为页面 P 上的每个链接分配等量的信用:因此(100(P 信用)-10(10% 税))/10(链接)=每个链接 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://***.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 我确定你是......但我注意到它主要是 *** 上的开发人员,我们喜欢自己做,这就是我们在这里的原因! :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】:

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

【讨论】:

以上是关于设计一个网络爬虫的主要内容,如果未能解决你的问题,请参考以下文章

Python网络爬虫课程设计

设计一个网络爬虫

Java网络爬虫怎么实现?

5 04 | 网页爬虫设计:如何下载千亿级网页?

伪分布式网络爬虫框架的设计与自定义实现

网络爬虫:中国大学排名定向爬虫