【问题标题】:PHP Crawler going in Infinite LoopPHP爬虫进入无限循环
【发布时间】:2018-04-09 17:30:56
【问题描述】:

这是我正在尝试构建的整个爬虫代码。此代码是单域爬虫。但它有一个大问题,当我检查数据库时,它一次又一次地保存一些链接,这会创建一个无限循环。我想在不使用我的数据库的情况下解决这个问题,因为在我的数据库中检查每个链接是否存在会使这个爬虫变慢。我怎样才能做到这一点? + 如果您有任何建议可以让它更快?

<?php

include_once('ganon.php');

ini_set('display_errors', '1');
function gethost($link)
{
    $link = trim($link, '/');
    if (!preg_match('#^http(s)?://#', $link)) 
    {
        $link = 'http://' . $link;
    }
    $urlParts = parse_url($link);
    $domain = preg_replace('/^www\./', '', $urlParts['host']);
    return $domain;
}

function store($raw, $link)
{
    $html = str_get_dom($raw);
    $title = $html('title', 0)->getPlainText();

    $con = @mysqli_connect('somehost', 'someuser', 'somepassword', 'somedatabase');
    if (!$con) 
    {
        echo "Error: " . mysqli_connect_error();
        exit();
    }

    $query = "INSERT INTO `somedatabase`.`sometable` (`title`, `url`) VALUES ('$title', '$link');";
    mysqli_query($con, $query);

    mysqli_close($con);
    echo $title."<br>";
}

function crawl_save_crawl($target)
{
    $curl = curl_init($target);
    curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
    curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true);
    $result = curl_exec($curl);
    if(curl_errno($curl)) 
    {
        echo 'Curl error: ' . curl_error($curl);
    }
    curl_close($curl); 


    $dom = str_get_dom($result);
    foreach($dom('a') as $element)
    {
        $href = $element->href;
        if (0 !== strpos($href, 'http')) 
        {
            $path = '/' . ltrim($href, '/');
            if (extension_loaded('http')) 
            {
                $href = http_build_url("http://www.".gethost($target), array('path' => $path));
            }   
            else 
            {
                $parts = parse_url("http://www.".gethost($target));
                $href = $parts['scheme'] . '://';
                if (isset($parts['user']) && isset($parts['pass'])) 
                {
                    $href .= $parts['user'] . ':' . $parts['pass'] . '@';
                }   
                $href .= $parts['host'];
                if (isset($parts['port'])) 
                {
                    $href .= ':' . $parts['port'];
                }
                $href .= dirname($parts['path'], 1).$path;
            }   
        }
        if (gethost($target) == gethost($href))
        {
            crawl_save_crawl($href);
        }
    }
    store($result, $target);        
}

$url=$_GET['u'];
crawl_save_crawl($url); 

?>

【问题讨论】:

  • 这个问题有点宽泛——你能指定/解释得更好吗?
  • 问题出在前:- 我试图抓取 google.com,然后我在我的数据库中看到它完美地抓取了 google.com,之后它开始抓取第一个链接。让第一个链接是 google.com/signin 。在这个登录页面上再次有一个链接 www.google.com 所以它再次开始抓取 google.com 并再次找到登录链接.....因此无限循环@rammelmueller
  • 让这个过程更快的一件事是连接到数据库一次(在调用crawl_save_crawl()之前)并通过连接。

标签: php database loops foreach web-crawler


【解决方案1】:

在您的crawl_save_crawl() 函数中,您可以存储您已经访问过的链接,从而停止返回它们的代码。使用静态变量并不理想,但在如此有限的一段代码中,它可以达到预期的目的(在调用中保持它的值)。

这不会阻止它搜索其他页面搜索过的东西,但会阻止它自身循环。

function crawl_save_crawl($target)
{
    static $alreadyDone = null;
    if ( $alreadyDone == null ) {
        $alreadyDone = [$target];
    }

在第一个循环中,这将添加当前引用,因为这会导致它丢失。

那么在你调用同一个路由之前,你可以测试一下它是否已经被检查...

$visit = trim(str_replace(["http://","https://"], "", $href), '/');
if (in_array($visit, $alreadyDone) === false &&
    gethost($target) == gethost($href))
{
    $alreadyDone[] = $visit;
    crawl_save_crawl($href);
}

这可能看起来仍然像是在访问同一个页面,但您的逻辑有时会创建一个带有“www.”的 href。一开始,这可能与没有它不同。所以在爬取stackoverflow的时候,这意味着有stackoverflow.com和www.stackoverflow.com。

【讨论】:

  • 我怎样才能得到 http 或 https 删除的 url
  • 别担心,先检查其余的工作是否正常。
  • 这不起作用仍然在没有错误的循环中进行
  • 你能告诉我你尝试的 URL 吗?
  • 仍然没有工作...它在数据库中保存了 4 次“...https://...www...stackoverflow.com”。我用这个查询 SELECT * FROM jdindex where url="...https://....www....stackoverflow.com" [我添加了点,因为 https 和 www 没有在评论中显示]
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-04-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多