Автор оригинала: 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(); Setlinks = 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.WebCrawlerFactoryfactory = 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.WebCrawlerFactoryfactory = () -> 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(); Setlinks = htmlParseData.getOutgoingUrls(); stats.incrementTotalLinksCount(links.size()); // do something with collected data } }
Теперь давайте вернемся к нашему контроллеру и предоставим Html-искателю экземпляр Статистики искателя :
CrawlerStatistics stats = new CrawlerStatistics(); CrawlController.WebCrawlerFactoryfactory = () -> 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.WebCrawlerFactoryhtmlFactory = () -> 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 .