Как я могу сделать функцию, которая повторяется, пока не найдет ВСЕ данные? - PullRequest
2 голосов
/ 18 июля 2010

Я хочу создать функцию PHP, которая просматривает домашнюю страницу веб-сайта, находит все ссылки на домашней странице, просматривает найденные ссылки и продолжает работать до тех пор, пока все ссылки на указанном веб-сайте не станут окончательными.Мне действительно нужно создать что-то вроде этого, чтобы я мог разбить мою сеть сайтов и предоставить «одну остановку» для поиска.

Вот что я получил до сих пор -

function spider($urltospider, $current_array = array(), $ignore_array = array('')) {
    if(empty($current_array)) {
        // Make the request to the original URL
        $session = curl_init($urltospider);
        curl_setopt($session, CURLOPT_RETURNTRANSFER, true);
        $html = curl_exec($session);
        curl_close($session);
        if($html != '') {
            $dom = new DOMDocument();
            @$dom->loadHTML($html);
            $xpath = new DOMXPath($dom);
            $hrefs = $xpath->evaluate("/html/body//a");
            for($i = 0; $i < $hrefs->length; $i++) {
                $href = $hrefs->item($i);
                $url = $href->getAttribute('href');
                if(!in_array($url, $ignore_array) && !in_array($url, $current_array)) {
                    // Add this URL to the current spider array
                    $current_array[] = $url;
                }
            }               
        } else {
            die('Failed connection to the URL');
        }
    } else {
        // There are already URLs in the current array
        foreach($current_array as $url) {
            // Connect to this URL

            // Find all the links in this URL

            // Go through each URL and get more links
        }
    }
}

ЕдинственноеПроблема в том, что я не могу понять, как действовать дальше.Может кто-нибудь мне помочь?По сути, эта функция будет повторяться до тех пор, пока все не будет найдено.

Ответы [ 4 ]

3 голосов
/ 18 июля 2010

Я не эксперт по PHP, но вы, кажется, слишком усложняете это.

function spider($urltospider, $current_array = array(), $ignore_array = array('')) {
    if(empty($current_array)) {
        $current_array[] =  $urltospider;
    $cur_crawl = 0;
    while ($cur_crawl < len($current_array)) { //don't use foreach because that can get messed up if you change the array while inside the loop.
        $links_found = crawl($current_array($cur_crawl)); //crawl should return all links found in the given page
        //Now keep adding $links_found to $current_array. Maybe you can check if any of the links found are already in $current_array so you don't crawl them multiple times
        $current_array = array_merge($current_array, $links_found);
        $cur_crawl += 1;
    }
return $current_array;
}
2 голосов
/ 18 июля 2010

То, что вы (вероятно) хотите использовать, называется «рекурсия».

Веб-страницы - это графики.Существует несколько алгоритмов трансверсальности графов;самое простое для понимания - глубина в начале.

Скажем, ваш сайт выглядит так (рекурсия прекращена):

* http://example.com/
  * http://example.com/
    * ...
  * http://example.com/post/1/
    * http://example.com/
      * ...
    * http://example.com/about/
      * ...
    * http://example.com/archives/
      * ...
  * http://example.com/post/2/
    * http://example.com/
      * ...
    * http://example.com/about/
      * ...
    * http://example.com/archives/
      * ...
  * http://example.com/post/3/
    * http://example.com/
      * ...
    * http://example.com/about/
      * ...
    * http://example.com/archives/
      * ...
  * http://example.com/about/
    * http://example.com/
      * ...
    * http://example.com/archives/
  * http://example.com/archives/
    * http://example.com/
      * ...
    * http://example.com/about/
      * ...
    * http://example.com/post/1/
      * http://example.com/
        * ...
      * http://example.com/about/
        * ...
      * http://example.com/archives/
        * ...
    * http://example.com/post/2/
      * http://example.com/
        * ...
      * http://example.com/about/
        * ...
      * http://example.com/archives/
        * ...
    * http://example.com/post/3/
      * http://example.com/
        * ...
      * http://example.com/about/
        * ...
      * http://example.com/archives/
        * ...
    * http://example.com/post/4/
      * http://example.com/
        * ...
      * http://example.com/about/
        * ...
      * http://example.com/archives/
        * ...
    * http://example.com/post/5/
      * http://example.com/
        * ...
      * http://example.com/about/
        * ...
      * http://example.com/archives/
        * ...

Когда вы впервые нажимаете http://example.com/,, у вас естьследующие ссылки:

Вам необходимо отслеживать страницы, которые вы уже посетили, чтобы их можно было игнорировать.(В противном случае это заняло бы целую вечность паука страницы ... буквально.) Вы добавляете в список игнорирования каждый раз, когда вы посещаете страницу.Прямо сейчас единственная запись в списке игнорирования - это http://example.com/.

Далее вы отфильтровываете игнорируемые ссылки, сокращая список до:

Затем вы снова запускаете сборщик на каждом изэти ссылки.Вы делаете это, вызывая вашу функцию снова, с текущим URL и списком игнорируемых сообщений: spider($url, &$ignoredUrls) (Мы используем ссылку на $ignoredUrls, поэтому вновь игнорируемые элементы видны родительским вызовам spider.)

Глядя на http://example.com/post/1/,, мы видим следующие ссылки:

Мы уже рассмотрели http://example.com/. Следующая ссылка, которая не игнорируется, - это страница about.Со страницы about мы переходим на страницу архивов, где просматриваем каждое сообщение.Каждый пост имеет одинаковый набор ссылок:

Потому что мыуже посетили все эти ссылки, мы возвращаем пустой массив.

Вернемся к /archives/, мы добавляем ссылку /post/2/ (первая незамеченная ссылка в /archives/) к локальной $foundLinksпеременная, а также возвращаемое значение вызова spider on с /post/2/ (который является пустым массивом).Затем мы переходим ко второму сообщению.

Когда мы просматриваем все наши сообщения, мы возвращаем $foundLinks.Страница /about/ затем добавляет эти ссылки к своей собственной $foundLinks, в дополнение к ссылке /about/.Поток возвращается к /post/1/, который смотрит на /archives/ (который теперь игнорируется).Паук /posts/1/ теперь завершен и возвращает свой собственный $foundLinks.В конце концов, исходный вызов получает все найденные ссылки.


Этот метод отлично работает для небольшого сайта, который полностью закрыт.Если вы перейдете по ссылке на Википедию, вы будете пауковать весь день.Вы можете бороться с этой проблемой по крайней мере двумя способами:

  1. Прекращение паутинга после определенной глубины (например, 10 ссылок).
  2. Ограничение URL-адресов, например, для определенного домена или субдомена(как example.com).

Вот быстрая реализация spider (не проверено):

function get_urls($url) {
    // curl/DOM code here
}

define('SPIDER_MAX_DEPTH', 10);

function spider_internal($url, &$ignoredUrls, $depth = 0) {
    $foundUrls = array($url);

    $ignoredUrls[] = $foundUrls;

    if($depth >= SPIDER_MAX_DEPTH) {
        return $foundUrls;
    }

    $links = get_links($url);

    foreach($links as $link) {
        if(array_search($link, $ignoredUrls) !== false) {
            continue;
        }

        $foundUrls = array_merge($foundUrls, spider($link, $ignoredUrls, $depth + 1));
    }

    return $foundUrls;
}

function spider($url) {
    $ignoredUrls = array();

    return spider_internal($url, $ignoredUrls);
}
2 голосов
/ 18 июля 2010

Слово, которое вы ищете, это рекурсия .В цикле foreach вы просто снова вызываете spider, и он будет вводить функцию для каждого URL-адреса и рекурсивно выполнять паутину.

Существует довольно серьезная проблема - у вас нет базового регистра, если только выв конечном итоге достичь страниц, которые не имеют ссылок на другие страницы (тупики).Эта функция будет работать вечно и не прекратит работу.Вам нужно связать его несколькими способами.

  1. Используйте memoization , чтобы запомнить результаты по URL-адресам, которые вы уже видели, вместо того, чтобы запрашивать одну и ту же страницу снова и снова.over.

  2. Ограничьте URL-адреса, которые вы будете посещать, определенным доменом, т. е. начинайте с 'http://www.somedomain.com', чтобы не допустить паузы во всем Интернете.

1 голос
/ 18 июля 2010

Вы определенно НЕ хотите использовать рекурсию при сканировании Интернета.:)

Хорошо работает для небольших сайтов, будет занимать всю доступную оперативную память на больших сайтах.Например, у вас достаточно ОЗУ для сканирования (и хранения ссылки на строку) для каждой ссылки на msn.com?Скорее всего нет.

...