Рубрики
Без рубрики

Руководство по Crawler4j

Узнайте, как использовать crawler4j для создания собственных веб-искателей.

Автор оригинала: Amy DeGregorio.

1. введение

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

В этом уроке мы узнаем, как использовать crawler4j для настройки и запуска наших собственных веб-искателей. crawler4j-это Java-проект с открытым исходным кодом, который позволяет нам легко это сделать.

2. Настройка

Давайте используем Maven Central , чтобы найти самую последнюю версию и ввести зависимость Maven:


    edu.uci.ics
    crawler4j
    4.4.0

3. Создание искателей

3.1. Простой HTML-искатель

Мы начнем с создания базового искателя, который будет сканировать HTML-страницы https://baeldung.com .

Давайте создадим наш искатель, расширив WebCrawler в нашем классе искателя и определив шаблон для исключения определенных типов файлов:

public class HtmlCrawler extends WebCrawler {

    private final static Pattern EXCLUSIONS
      = Pattern.compile(".*(\\.(css|js|xml|gif|jpg|png|mp3|mp4|zip|gz|pdf))$");

    // more code
}

В каждом классе искателя мы должны переопределить и реализовать два метода: должен посетить и посетить .

Давайте создадим наш должен посетить метод теперь, используя шаблон ИСКЛЮЧЕНИЯ , который мы создали:

@Override
public boolean shouldVisit(Page referringPage, WebURL url) {
    String urlString = url.getURL().toLowerCase();
    return !EXCLUSIONS.matcher(urlString).matches() 
      && urlString.startsWith("https://www.baeldung.com/");
}

Затем мы можем выполнить вашу обработку посещенных страниц в методе visit :

@Override
public void visit(Page page) {
    String url = page.getWebURL().getURL();

    if (page.getParseData() instanceof HtmlParseData) {
        HtmlParseData htmlParseData = (HtmlParseData) page.getParseData();
        String title = htmlParseData.getTitle();
        String text = htmlParseData.getText();
        String html = htmlParseData.getHtml();
        Set links = htmlParseData.getOutgoingUrls();

        // do something with the collected data
    }
}

После того, как мы написали наш искатель, нам нужно настроить и запустить его:

File crawlStorage = new File("src/test/resources/crawler4j");
CrawlConfig config = new CrawlConfig();
config.setCrawlStorageFolder(crawlStorage.getAbsolutePath());

int numCrawlers = 12;

PageFetcher pageFetcher = new PageFetcher(config);
RobotstxtConfig robotstxtConfig = new RobotstxtConfig();
RobotstxtServer robotstxtServer= new RobotstxtServer(robotstxtConfig, pageFetcher);
CrawlController controller = new CrawlController(config, pageFetcher, robotstxtServer);

controller.addSeed("https://www.baeldung.com/");

CrawlController.WebCrawlerFactory factory = HtmlCrawler::new;

controller.start(factory, numCrawlers);

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

Следует также отметить, что метод CrawlController.start() является блокирующей операцией . Любой код после этого вызова будет выполняться только после завершения работы искателя.

3.2. ImageCrawler

По умолчанию crawler4j не сканирует двоичные данные. В следующем примере мы включим эту функцию и просканируем все JPEG-файлы на Baeldung.

Давайте начнем с определения класса Image Crawler с конструктором, который принимает каталог для сохранения изображений:

public class ImageCrawler extends WebCrawler {
    private final static Pattern EXCLUSIONS
      = Pattern.compile(".*(\\.(css|js|xml|gif|png|mp3|mp4|zip|gz|pdf))$");
    
    private static final Pattern IMG_PATTERNS = Pattern.compile(".*(\\.(jpg|jpeg))$");
    
    private File saveDir;
    
    public ImageCrawler(File saveDir) {
        this.saveDir = saveDir;
    }

    // more code

}

Далее, давайте реализуем метод должен посетить :

@Override
public boolean shouldVisit(Page referringPage, WebURL url) {
    String urlString = url.getURL().toLowerCase();
    if (EXCLUSIONS.matcher(urlString).matches()) {
        return false;
    }

    if (IMG_PATTERNS.matcher(urlString).matches() 
        || urlString.startsWith("https://www.baeldung.com/")) {
        return true;
    }

    return false;
}

Теперь мы готовы реализовать метод visit :

@Override
public void visit(Page page) {
    String url = page.getWebURL().getURL();
    if (IMG_PATTERNS.matcher(url).matches() 
        && page.getParseData() instanceof BinaryParseData) {
        String extension = url.substring(url.lastIndexOf("."));
        int contentLength = page.getContentData().length;

        // write the content data to a file in the save directory
    }
}

Запуск нашего обходчика изображений аналогичен запуску Http-обходчика , но нам нужно настроить его для включения двоичного содержимого:

CrawlConfig config = new CrawlConfig();
config.setIncludeBinaryContentInCrawling(true);

// ... same as before
        
CrawlController.WebCrawlerFactory factory = () -> new ImageCrawler(saveDir);
        
controller.start(factory, numCrawlers);

3.3. Сбор Данных

Теперь, когда мы рассмотрели несколько основных примеров, давайте подробнее рассмотрим ваш Html-искатель , чтобы собрать некоторые основные статистические данные во время нашего обхода.

Во-первых, давайте определим простой класс для хранения нескольких статистических данных:

public class CrawlerStatistics {
    private int processedPageCount = 0;
    private int totalLinksCount = 0;
    
    public void incrementProcessedPageCount() {
        processedPageCount++;
    }
    
    public void incrementTotalLinksCount(int linksCount) {
        totalLinksCount += linksCount;
    }
    
    // standard getters
}

Далее, давайте изменим наш Html-искатель , чтобы принять Статистику искателя экземпляр через конструктор:

private CrawlerStatistics stats;
    
public HtmlCrawler(CrawlerStatistics stats) {
    this.stats = stats;
}

С помощью нашего нового объекта Crawler Statistics давайте изменим метод visit , чтобы собрать то, что мы хотим:

@Override
public void visit(Page page) {
    String url = page.getWebURL().getURL();
    stats.incrementProcessedPageCount();

    if (page.getParseData() instanceof HtmlParseData) {
        HtmlParseData htmlParseData = (HtmlParseData) page.getParseData();
        String title = htmlParseData.getTitle();
        String text = htmlParseData.getText();
        String html = htmlParseData.getHtml();
        Set links = htmlParseData.getOutgoingUrls();
        stats.incrementTotalLinksCount(links.size());

        // do something with collected data
    }
}

Теперь давайте вернемся к нашему контроллеру и предоставим Html-искателю экземпляр Статистики искателя :

CrawlerStatistics stats = new CrawlerStatistics();
CrawlController.WebCrawlerFactory factory = () -> new HtmlCrawler(stats);

3.4. Несколько искателей

Основываясь на наших предыдущих примерах, давайте теперь посмотрим, как мы можем запускать несколько искателей с одного и того же контроллера.

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

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

До сих пор мы использовали метод CrawlController.start для запуска наших искателей и отметили, что это метод блокировки. Для запуска кратных мы будем использовать Crawlercontroller.start Non Blocking в сочетании с CrawlController.waitUntilFinish .

Теперь давайте создадим контроллер для одновременного запуска Html Crawler и Image Crawler :

File crawlStorageBase = new File("src/test/resources/crawler4j");
CrawlConfig htmlConfig = new CrawlConfig();
CrawlConfig imageConfig = new CrawlConfig();
        
// Configure storage folders and other configurations
        
PageFetcher pageFetcherHtml = new PageFetcher(htmlConfig);
PageFetcher pageFetcherImage = new PageFetcher(imageConfig);
        
RobotstxtConfig robotstxtConfig = new RobotstxtConfig();
RobotstxtServer robotstxtServer = new RobotstxtServer(robotstxtConfig, pageFetcherHtml);

CrawlController htmlController
  = new CrawlController(htmlConfig, pageFetcherHtml, robotstxtServer);
CrawlController imageController
  = new CrawlController(imageConfig, pageFetcherImage, robotstxtServer);
        
// add seed URLs
        
CrawlerStatistics stats = new CrawlerStatistics();
CrawlController.WebCrawlerFactory htmlFactory = () -> new HtmlCrawler(stats);
        
File saveDir = new File("src/test/resources/crawler4j");
CrawlController.WebCrawlerFactory imageFactory
  = () -> new ImageCrawler(saveDir);
        
imageController.startNonBlocking(imageFactory, 7);
htmlController.startNonBlocking(htmlFactory, 10);

htmlController.waitUntilFinish();
imageController.waitUntilFinish();

4. Конфигурация

Мы уже видели кое-что из того, что мы можем настроить. Теперь давайте рассмотрим некоторые другие общие настройки.

Настройки применяются к экземпляру CrawlConfig , который мы указываем в нашем контроллере.

4.1. Ограничение Глубины Обхода

По умолчанию наши сканеры будут ползти так глубоко, как только смогут. Чтобы ограничить глубину их проникновения, мы можем установить глубину обхода:

crawlConfig.setMaxDepthOfCrawling(2);

Исходные URL-адреса считаются на глубине 0, поэтому глубина обхода 2 будет выходить на два слоя за пределы исходного URL-адреса.

4.2. Максимальное количество страниц для извлечения

Еще один способ ограничить количество страниц, которые будут охватывать наши сканеры, – установить максимальное количество страниц для обхода:

crawlConfig.setMaxPagesToFetch(500);

4.3. Максимальное Количество Исходящих Ссылок

Мы также можем ограничить количество исходящих ссылок на каждой странице:

crawlConfig.setMaxOutgoingLinksToFollow(2000);

4.4. Задержка Вежливости

Поскольку очень эффективные сканеры могут легко создавать нагрузку на веб-серверы, crawler4j имеет то, что он называет задержкой вежливости. По умолчанию он установлен на 200 миллисекунд. При необходимости мы можем скорректировать это значение:

crawlConfig.setPolitenessDelay(300);

4.5. Включить Двоичный контент

Мы уже использовали опцию для включения двоичного контента в наш Обходчик изображений :

crawlConfig.setIncludeBinaryContentInCrawling(true);

4.6. Включить HTTPS

По умолчанию искатели будут включать страницы HTTPS, но мы можем отключить это:

crawlConfig.setIncludeHttpsPages(false);

4.7. Возобновляемый Обход

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

crawlConfig.setResumableCrawling(true);

4.8. Строка Агента пользователя

Строка агента пользователя по умолчанию для crawler4j – crawler4j . Давайте настроим это:

crawlConfig.setUserAgentString("baeldung demo (https://github.com/yasserg/crawler4j/)");

Мы только что рассмотрели здесь некоторые основные конфигурации. Мы можем посмотреть на Crawlconfig class, если нас интересуют некоторые из более продвинутых или неясных параметров конфигурации.

5. Заключение

В этой статье мы использовали crawler4j для создания собственных веб-искателей. Мы начали с двух простых примеров обхода HTML и изображений. Затем мы построили на этих примерах, чтобы увидеть, как мы можем собирать статистику и запускать несколько искателей одновременно.

Полные примеры кода доступны на GitHub .