Как написать гусеничный? - PullRequest
61 голосов
/ 19 сентября 2008

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

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

Ответы [ 10 ]

146 голосов
/ 19 сентября 2008

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

  • Список не посещенных 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
        }
    }
}
29 голосов
/ 19 декабря 2011

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

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

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

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

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

  • Сканирование с нескольких компьютеров

  • Неправильные коды HTML

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

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

  • Процедуры повторного сканирования и приоритеты.

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

И некоторые важные вещи

  • Респект robots.txt

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

8 голосов
/ 12 декабря 2012

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

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

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

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

Алгоритм основного веб-сканера: -

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

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

     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;
         }
      }
    

5 голосов
/ 19 сентября 2008

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

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

Некоторые проблемы (есть и другие):

  • Черные дыры (как описано)
  • Повтор (что если вы получите 500?)
  • Перенаправление
  • Контроль потока (иначе вы можете быть бременем на сайтах)
  • Реализация robots.txt
5 голосов
/ 19 сентября 2008

Гусеницы просты в концепции.

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

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

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

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

4 голосов
/ 19 сентября 2008

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

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

2 голосов
/ 19 сентября 2008

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

1 голос
/ 29 июня 2012

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

0 голосов
/ 07 июня 2013

Я сделал простой веб-сканер, используя реактивное расширение в .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"));
0 голосов
/ 19 сентября 2008

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...