Как написать краулер?

У меня была мысль написать простой поисковый робот, который мог бы сканировать и выдавать список своих результатов для веб-сайтов и контента нашей НКО.

Есть ли у кого-нибудь мысли, как это сделать? Куда вы указываете поисковому роботу, чтобы начать работу? Как он отправляет свои выводы и продолжает сканировать? Как он узнает, что он нашел, и т. Д. И т. Д.


person Community    schedule 19.09.2008    source источник


Ответы (10)


Вы, конечно, будете изобретать велосипед. Но вот основы:

  • Список непосещенных URL-адресов - заполните его одной или несколькими стартовыми страницами.
  • Список посещенных URL-адресов - так что вы не ходите по кругу
  • Набор правил для URL-адресов, которые вам не интересны - поэтому вы не индексируете весь Интернет

Поместите их в постоянное хранилище, чтобы вы могли остановить и запустить поисковый робот без потери состояния.

Алгоритм такой:

while(list of unvisited URLs is not empty) {
    take URL from list
    remove it from the unvisited list and add it to the visited list
    fetch content
    record whatever it is you want to about the content
    if content is HTML {
        parse out URLs from links
        foreach URL {
           if it matches your rules
              and it's not already in either the visited or unvisited list
              add it to the unvisited list
        }
    }
}
person slim    schedule 19.09.2008
comment
Отличный ответ, но когда вы говорите «изобретать колесо», где именно находятся бесплатные фреймворки для веб-сканеров с открытым исходным кодом? возможно для Java, но я не нашел ни одного для .net. - person Anonymous Type; 06.10.2010
comment
Ух, слишком рано нажать Enter. По этой ссылке есть несколько хороших, ни один из которых не является .Net. Однако я не совсем понимаю, почему вы решили ограничиться .Net. - person slim; 07.10.2010
comment
привет, я наткнулся на этот ответ, и я подумал, что вы можете дать мне некоторое представление о разработке веб-сканера. Предполагая, что я выполнил вышеуказанные шаги, что произойдет, если я посетил все URL-адреса? мне выйти из цикла while и завершить сценарий? или вы запускаете его как демон или просто цикл while, чтобы снова получить непосещенные URL-адреса? - person chrizonline; 28.07.2014
comment
аааа, первое, что вы можете сделать в цикле while, - это добавить URL-адрес в _2 _... иначе вы можете попасть в бесконечный цикл, если две страницы ссылаются друг на друга ... - person CpILL; 18.02.2018
comment
@CpILL Вы правы - прошло 9 лет, чтобы кто-то заметил. Исправлено сейчас. - person slim; 19.02.2018

Сложная часть краулера - это если вы хотите масштабировать его для огромного количества веб-сайтов / запросов. В этой ситуации вам придется столкнуться с некоторыми проблемами, такими как:

  • Невозможность хранить всю информацию в одной базе данных.

  • Недостаточно ОЗУ для работы с огромными индексами

  • Многопоточность и параллелизм

  • Ловушки краулера (бесконечный цикл, созданный изменением URL-адресов, календарей, идентификаторов сессий ...) и дублированного контента.

  • Сканирование с более чем одного компьютера

  • Некорректные HTML-коды

  • Постоянные HTTP-ошибки с серверов

  • Базы данных без сжатия, что увеличивает потребность в пространстве примерно в 8 раз.

  • Пересмотрите процедуры и приоритеты.

  • Используйте запросы со сжатием (Deflate / gzip) (подходит для любого краулера).

И несколько важных вещей

  • Уважайте robots.txt

  • И задержка краулера на каждый запрос, чтобы не задушить веб-серверы.

person lexmooze    schedule 19.12.2011
comment
Отличный ответ! Вы можете решить проблемы с оперативной памятью, используя фильтр Блума. - person arachnode.net; 04.03.2013
comment
Я думаю, что ответ на первые 1-3 и 5 - это AWS от Amazon. Хеширование может решить проблему «дублированного контента». Библиотека парсинга, такая как Beautiful Soup, может обрабатывать 6. 7 - проверьте заголовки http. 8 - использовать базу данных со сжатием. и т.д - person CpILL; 18.02.2018

Многопоточный веб-сканер

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

Многопоточный поисковый робот нуждается в двух структурах данных: linksVisited (это должно быть реализовано как хэш-карта или trai) и linksToBeVisited (это очередь).

Поисковый робот использует BFS для обхода всемирной паутины.

Алгоритм базового поискового робота: -

  1. Добавьте один или несколько исходных URL-адресов в linksToBeVisited. Метод добавления URL-адреса в linksToBeVisited должен быть синхронизирован.
  2. Извлечь элемент из linksToBeVisited и добавить его в linksVisited. Этот метод pop для извлечения url-адреса из linksToBeVisited должен быть синхронизирован.
  3. Загрузите страницу из Интернета.
  4. Разберите файл и добавьте любую до сих пор не посещенную ссылку, найденную на странице, в linksToBeVisited. При необходимости URL-адреса могут быть отфильтрованы. Пользователь может указать набор правил для фильтрации URL-адресов для сканирования.
  5. Необходимая информация, найденная на странице, сохраняется в базе данных или файле.
  6. повторяйте шаги со 2 по 5, пока очередь не станет пустой.

    Вот фрагмент кода о том, как синхронизировать потоки ....

     public void add(String site) {
       synchronized (this) {
       if (!linksVisited.contains(site)) {
         linksToBeVisited.add(site);
         }
       }
     }
    
     public String next() {
        if (linksToBeVisited.size() == 0) {
        return null;
        }
           synchronized (this) {
            // Need to check again if size has changed
           if (linksToBeVisited.size() > 0) {
              String s = linksToBeVisited.get(0);
              linksToBeVisited.remove(0);
              linksVisited.add(s);
              return s;
           }
         return null;
         }
      }
    

person alienCoder    schedule 12.12.2012
comment
Или вы можете просто использовать node.js асинхронно. - person Totty.js; 13.06.2013
comment
Здесь мы говорим о крупномасштабных краулерах, для такого краулера нельзя использовать javascript. Лучшая практика - c или c ++, java тоже работает хорошо. - person alienCoder; 03.04.2014
comment
Почему вы говорите, что js не масштабируется? Можете показать мне какие-нибудь доказательства, пожалуйста? - person Totty.js; 03.04.2014
comment
Да ладно, javascript - это интерпретируемый динамический язык, который полностью работает в веб-браузере, поэтому производительность и масштабируемость зависят от возможностей браузера. Если вы создадите много потоков, браузер зависнет. Javascript хорош для веб-приложений (и для некоторых игрушечных программ), но не для крупномасштабных приложений. Если вы хотите написать игрушечный сканер, тогда это нормально, но когда дело доходит до обработки реальных многопоточных приложений (здесь вам придется иметь дело с TB и PB), то javascript не может даже приблизиться к компилируемым языкам. - person alienCoder; 03.04.2014
comment
Думаю, вы даже не слышали о node.js: google.pt/ поиск? q = node.js + linkedin - person Totty.js; 03.04.2014
comment
Я знаю node.js и его популярность из-за его масштабируемости, но я думаю, вы упустили мою точку зрения - он все же работает в веб-браузере, поэтому масштабируемость и производительность все зависит от возможностей веб-браузера. :) Можете ли вы привести мне хоть один крупномасштабный пример из реальной жизни, где js использовался вместо скомпилированных языков? - person alienCoder; 04.04.2014
comment
Во-первых, node.js не запускается в браузере, вам не нужен браузер для запуска приложений node.js. Крупномасштабные примеры из реального мира (связанные с мобильными устройствами, как сказано в моем ответе выше): google.pt/search?q=Large+scale+real+world+examples+node.js, github.com/joyent/node/wiki/, venturebeat.com/2011/08/16/linkedin-node - person Totty.js; 04.04.2014
comment
Теперь это новая теория :). Итак, вы говорите мне, что node.js не работает в веб-браузере, а ссылка на него построена на javascript. Для ur-информации серверная часть linkedin - это java (не js, есть разница между java и js), передняя часть использует HTML5 и js slideshare.net/linkedin/linkedins-communication-architecture. - person alienCoder; 04.04.2014
comment
Я не знаю, как вам сказать, но javascript может работать как на сервере, так и на стороне клиента, лол, пожалуйста, проснись, чувак! Вы читали то, что я вам рассказал (venturebeat.com/2011/08/16 / linkedin-node, на стороне сервера весь наш стек мобильного программного обеспечения полностью построен на Node,)? Что такое node.js: nodejs.org. Ты должно быть шутишь! - person Totty.js; 04.04.2014
comment
Хорошая шутка :) Node.js - это платформа, построенная на среде выполнения JavaScript в Chrome - nodejs.org. Независимо от того, запускаете ли вы его на стороне сервера или на стороне клиента, он работает в Google v8 (кстати, он написан на C ++ :)). Это бэкэнд C ++, который дает ему силу, node.js использует возможности C ++ для создания масштабируемых веб-приложений. Для веб-приложений это хорошо, но краулер - это не веб-приложение. Для поискового робота лучше всего подходят скомпилированные языки. C ++, Java намного быстрее, чем node.js (конечно, J2EE в некоторых случаях медленнее, чем node.js, но для веб-краулера нам не нужен J2EE). - person alienCoder; 05.04.2014
comment
Вот несколько причин, по которым мы не должны использовать node.js для создания настоящего веб-сканера (конечно, вы можете создать игрушечный сканер): - person alienCoder; 05.04.2014
comment
1. node.js является однопоточным. 2. Полностью зависит от V8. 3. Отладка JavaScript на Node.js болезненна. 4.JavaScript - интерпретируемый язык, код медленнее, чем C ++. 5. Для веб-краулера не нужно делать его веб-приложением. 6. API Node.js имеет привычку меняться обратно несовместимыми способами от выпуска к выпуску. - person alienCoder; 05.04.2014
comment
7.JavaScript - это язык с прекрасным ядром, но абсолютно анемичная стандартная библиотека. 8. отсутствие внутренней организации кода является огромным недостатком и т. Д. И т. Д. Реальный поисковый робот - это не простая программа, ему приходится решать множество проблем. Но для простого краулера можно использовать node.js. - person alienCoder; 05.04.2014

По сути, краулеры просты.

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

Вы можете использовать заголовок Content-type, чтобы узнать, какой тип содержимого, и ограничить поисковый робот только синтаксическим анализом типов HTML.

Вы можете вырезать HTML-теги, чтобы получить простой текст, который вы можете анализировать (чтобы получить теги и т. Д., Основную часть страницы). Вы даже можете сделать это с тегами alt / title для изображений, если у вас есть опыт.

А в фоновом режиме у вас может быть пул потоков, которые потребляют URL-адреса из очереди и делают то же самое. Конечно, вы хотите ограничить количество потоков.

person JeeBee    schedule 19.09.2008

Если сайты вашей НКО относительно большие или сложные (с динамическими страницами, которые фактически создают «черную дыру», например, календарь со ссылкой «на следующий день»), вам лучше использовать настоящий веб-сканер, например Heritrix.

Если на сайтах всего несколько страниц, вы можете обойтись простым использованием curl, wget или вашего собственного. Просто помните, если они начнут расти или вы начнете усложнять свой сценарий, чтобы просто использовать настоящего краулера или, по крайней мере, посмотреть на его источник, чтобы узнать, что они делают и почему.

Некоторые проблемы (их больше):

  • Черные дыры (как описано)
  • Повторные попытки (что, если вы получите 500?)
  • Перенаправления
  • Контроль потока (иначе вы можете быть обузой на сайтах)
  • реализация robots.txt
person Vinko Vrsalovic    schedule 19.09.2008
comment
Не могли бы вы рассказать немного о том, как справляться с упомянутыми вами проблемами? В частности, черные дыры? - person Shabbyrobe; 18.05.2009
comment
Обычный выход из черных дыр - это программирование настраиваемого предела для каждого домена или URL-адреса, соответствующего регулярному выражению (т. Е., Если URL-адрес совпадает с этим или доменом является то, переходите после 1000 найденных совпадающих страниц). Управление потоком обычно осуществляется в количестве страниц в секунду для каждого домена (обычно они заставляют вас ждать более одной секунды, чтобы не быть обузой). - person Vinko Vrsalovic; 18.05.2009

В Википедии есть хорошая статья о поисковых роботах, охватывающая многие алгоритмы и рекомендации.

Однако я бы не стал писать собственный поисковый робот. Это большая работа, и поскольку вам нужен только «простой сканер», я думаю, все, что вам действительно нужно, это стандартный поисковый робот. Существует множество бесплатных поисковых роботов с открытым исходным кодом, которые, вероятно, сделают все, что вам нужно, с очень небольшой работой с вашей стороны.

person Derek Park    schedule 19.09.2008

Вы можете составить список слов и создать цепочку для каждого слова, найденного в Google.
Затем каждый поток будет создавать новую цепочку для каждой ссылки, которую он найдет на странице.
Каждый поток должен записывать то, что он находит в база данных. Когда каждый поток заканчивает чтение страницы, он завершается.
И у вас есть очень большая база данных ссылок в вашей базе данных.

person Gero    schedule 19.09.2008
comment
плюс 1 за то, что смешно - person Kyle Zimmer; 02.06.2018

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

Изменить: или, может быть, curl вместо wget, но я не знаком с curl, я не знаю, выполняет ли он рекурсивные загрузки, такие как wget.

person whatsisname    schedule 19.09.2008

Я использую сервер открытого поиска для внутреннего поиска моей компании, попробуйте следующее: http://open-search-server.com это также открытая среда.

person Sathishkumar    schedule 29.06.2012

Я сделал простой веб-сканер, используя реактивное расширение в .net.

https://github.com/Misterhex/WebCrawler

public class Crawler
    {
    class ReceivingCrawledUri : ObservableBase<Uri>
    {
        public int _numberOfLinksLeft = 0;

        private ReplaySubject<Uri> _subject = new ReplaySubject<Uri>();
        private Uri _rootUri;
        private IEnumerable<IUriFilter> _filters;

        public ReceivingCrawledUri(Uri uri)
            : this(uri, Enumerable.Empty<IUriFilter>().ToArray())
        { }

        public ReceivingCrawledUri(Uri uri, params IUriFilter[] filters)
        {
            _filters = filters;

            CrawlAsync(uri).Start();
        }

        protected override IDisposable SubscribeCore(IObserver<Uri> observer)
        {
            return _subject.Subscribe(observer);
        }

        private async Task CrawlAsync(Uri uri)
        {
            using (HttpClient client = new HttpClient() { Timeout = TimeSpan.FromMinutes(1) })
            {
                IEnumerable<Uri> result = new List<Uri>();

                try
                {
                    string html = await client.GetStringAsync(uri);
                    result = CQ.Create(html)["a"].Select(i => i.Attributes["href"]).SafeSelect(i => new Uri(i));
                    result = Filter(result, _filters.ToArray());

                    result.ToList().ForEach(async i =>
                    {
                        Interlocked.Increment(ref _numberOfLinksLeft);
                        _subject.OnNext(i);
                        await CrawlAsync(i);
                    });
                }
                catch
                { }

                if (Interlocked.Decrement(ref _numberOfLinksLeft) == 0)
                    _subject.OnCompleted();
            }
        }

        private static List<Uri> Filter(IEnumerable<Uri> uris, params IUriFilter[] filters)
        {
            var filtered = uris.ToList();
            foreach (var filter in filters.ToList())
            {
                filtered = filter.Filter(filtered);
            }
            return filtered;
        }
    }

    public IObservable<Uri> Crawl(Uri uri)
    {
        return new ReceivingCrawledUri(uri, new ExcludeRootUriFilter(uri), new ExternalUriFilter(uri), new AlreadyVisitedUriFilter());
    }

    public IObservable<Uri> Crawl(Uri uri, params IUriFilter[] filters)
    {
        return new ReceivingCrawledUri(uri, filters);
    }
}

и вы можете использовать его следующим образом:

Crawler crawler = new Crawler();
IObservable observable = crawler.Crawl(new Uri("http://www.codinghorror.com/"));
observable.Subscribe(onNext: Console.WriteLine, 
onCompleted: () => Console.WriteLine("Crawling completed"));
person Misterhex    schedule 07.06.2013