Вопрос по web-crawler, web-scraping, php, web – Ошибки относительно Web Crawler в PHP

2

Я пытаюсь создать простой веб-сканер, использующий PHP, который способен сканировать домены .edu, при условии, что исходные URL родительского.

Я использовал простой html dom для реализации сканера, в то время как некоторая основная логика реализована мной.

Я размещаю код ниже и постараюсь объяснить проблемы.

private function initiateChildCrawler($parent_Url_Html) {

    global $CFG;
    static $foundLink;
    static $parentID;
    static $urlToCrawl_InstanceOfChildren;

    $forEachCount = 0;
    foreach($parent_Url_Html->getHTML()->find('a') as $foundLink) 
    {
        $forEachCount++;
        if($forEachCount<500) {
        $foundLink->href = url_to_absolute($parent_Url_Html->getURL(), $foundLink->href);

        if($this->validateEduDomain($foundLink->href)) 
        {
            //Implement else condition later on
            $parentID = $this->loadSaveInstance->parentExists_In_URL_DB_CRAWL($this->returnParentDomain($foundLink->href));
            if($parentID != FALSE) 
            {
                if($this->loadSaveInstance->checkUrlDuplication_In_URL_DB_CRAWL($foundLink->href) == FALSE)
                {
                    $urlToCrawl_InstanceOfChildren = new urlToCrawl($foundLink->href);
                    if($urlToCrawl_InstanceOfChildren->getSimpleDomSource($CFG->finalContext)!= FALSE)
                    {
                        $this->loadSaveInstance->url_db_html($urlToCrawl_InstanceOfChildren->getURL(), $urlToCrawl_InstanceOfChildren->getHTML());
                        $this->loadSaveInstance->saveCrawled_To_URL_DB_CRAWL(NULL, $foundLink->href, "crawled", $parentID);

                        /*if($recursiveCount<1)
                        {
                            $this->initiateChildCrawler($urlToCrawl_InstanceOfChildren);
                        }*/
                    }
                }
            }
        }
        }
    }   
}

Теперь вы можете видеть, что initiateChildCrawler вызывается функцией initiateParentCrawler, которая передает родительскую ссылку на дочерний сканер. Пример родительской ссылки: www.berkeley.edu, для которой сканер найдет все ссылки на своей главной странице и вернет все html-содержимое. Это происходит до тех пор, пока не будут исчерпаны URL-адреса семян.

например: 1-harvard.edu - >>>>> Найдет все ссылки и вернет их HTML-контент (вызвав childCrawler). Переходит к следующему родителю в parentCrawler. 2-berkeley.edu - >>>>> Найдет все ссылки и вернет их html-контент (вызвав childCrawler).

Другие функции говорят сами за себя.

Теперь проблема: после того, как childCrawler завершает цикл foreach для каждой ссылки, функция не может правильно завершиться. Если я запускаю сценарий из CLI, CLI падает. При запуске скрипта в браузере скрипт завершается.

Но если я установлю предел сканирования дочерних ссылок равным 10 или менее (изменяя переменную $ forEachCount), сканер начнет работать нормально.

Пожалуйста, помогите мне в этом отношении.

Сообщение от CLI:

Подпись проблемы: Проблема Имя события: APPCRASH Имя приложения: php-cgi.exe Версия приложения: 5.3.8.0 Временная метка приложения: 4e537939 Имя модуля сбоя: php5ts.dll Версия модуля сбоя: 5.3.8.0 Временная метка модуля сбоя: 4e537a04 Код исключения: c0000005 Исключение Смещение: 0000c793 Версия ОС: 6.1.7601.2.1.0.256.48 Идентификатор локали: 1033 Дополнительная информация 1: 0a9e Дополнительная информация 2: 0a9e372d3b4ad19135b953a78882e789 Дополнительная информация 3: 0a9e Дополнительная информация 4: 0a9e372d3b4ad19135b9578a78882

$ Бен Ли, я понял вашу точку зрения ... но не могли бы вы объяснить мне термин плоская петля? Rafay
Что ж, теперь я делаю массив абсолютных URL-адресов, для которых нужно получить html. Проблема сейчас в том, что после получения и вставки около 50-60 URL-адресов и их HTML-содержимого я получаю сообщение об ошибке «Сервер MySQL ушел». Но если я ограничу количество запрашиваемых URL-адресов до меньшего числа, скажем, около 10-15, ошибка исчезнет. Пожалуйста, помогите мне в этом отношении. Rafay
Проблема в том, что вы используете слишком много памяти, не освобождая ее, потому что ваш метод потенциально может использовать до $ forEachCount уровней до глубины, то есть до $ forEachCount полных документов в памяти. Вы должны преобразовать это в плоский цикл. Ведите основной список URL-адресов, а также основной список «обработанных URL-адресов», затем перебирайте необработанные, загружая каждую страницу один раз и добавляя ссылки в основной список. Тогда у вас будет только один документ в памяти одновременно. Остановитесь, когда основной список достигнет желаемой длины. Ben Lee
Пожалуйста, отправьте сообщение об ошибке из-за сбоя CLI. Johnny Graber
Когда вы измените свой код, чтобы использовать плоский список, попробуйтеsleep(1) после разбора одного URL. Maby ваш дБ сервер слаб и не может обрабатывать много запросов одновременно. Кроме того, вы могли быecho некоторая отладочная информация в различных функциях, чтобы увидеть использование памяти, количество проанализированных URL и т. д. piotrekkr

Ваш Ответ

1   ответ
1

Вы запускаете цикл со стеком, который содержит все URL, которые вы хотите обработать в первую очередь.Внутри цикла:Высдвиг первый URL (вы получаете его, и он удален) из стека.Если вы найдете новые URL, вы добавляете их в конец стека (От себя).

Это будет выполняться до тех пор, пока все URL из стека не будут обработаны, поэтому вы добавляете (как вы уже как-то ужеforeach) счетчик, чтобы предотвратить это слишком долго:

$URLStack = (array) $parent_Url_Html->getHTML()->find('a');
$URLProcessedCount = 0;
while ($URLProcessedCount++ < 500) # this can run endless, so this saves us from processing too many URLs
{
    $url = array_shift($URLStack);
    if (!$url) break; # exit if the stack is empty

    # process URL

    # for each new URL:
    $URLStack[] = $newURL;
}

Вы можете сделать его еще более интеллектуальным, чем не добавлять URL-адреса в стек, которые уже существуют в нем, однако тогда вам нужно только вставить абсолютные URL-адреса в стек. Однако я настоятельно рекомендую вам сделать это, потому что нет необходимости обрабатывать страницу, которую вы уже получили снова (например, каждая страница содержит ссылку на домашнюю страницу, вероятно). Если вы хотите сделать это, просто увеличьте$URLProcessedCount внутри цикла, так что вы также сохраните предыдущие записи:

while ($URLProcessedCount < 500) # this can run endless, so this saves us from processing too many URLs
{
    $url = $URLStack[$URLProcessedCount++];

Дополнительно япредлагать вы используете PHPDOMDocument расширение вместо простого DOM, поскольку это гораздо более универсальный инструмент.

Если вы администратор базы данных, включите ведение журнала БД и проверьте, что происходит. Возможно, происходит что-то неверное, что можно решить, переконфигурировав mysql (или какую бы базу данных вы не использовали). hakre
Ваша база данных отказывается работать с вашим скриптом и разорвала соединение. На это могут быть разные причины, вам следует обратиться к администратору базы данных, чтобы выяснить, что именно происходит, возможно, вы достигли определенных ограничений у своего поставщика базы данных. hakre
Что ж, теперь я делаю массив абсолютных URL-адресов, для которых нужно получить html. Проблема сейчас в том, что после получения и вставки около 50-60 URL-адресов и их HTML-содержимого я получаю сообщение об ошибке «Сервер MySQL ушел». Но если я ограничу количество запрашиваемых URL-адресов до меньшего числа, скажем, около 10-15, ошибка исчезнет. Пожалуйста, помогите мне в этом отношении. Rafay
Я сам администратор базы данных. Код и база данных развернуты на моем собственном компьютере, и я не знаю, что делать, чтобы все сделать прямо здесь. Ирония в том, что база данных работает нормально с меньшим количеством ссылок (около 40-50), но возвращает ошибку при больших числах. Если бы скрипт был проблемой, ошибка появилась бы в самой первой ссылке. Rafay

Похожие вопросы