@@ -1,30 +1,16 @@
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				package   searchengine.services ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				import   lombok.RequiredArgsConstructor ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				import   org.jsoup.HttpStatusException ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				import   org.jsoup.Jsoup ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				import   org.jsoup.nodes.Document ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				import   org.slf4j.Logger ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				import   org.slf4j.LoggerFactory ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				import   org.springframework.dao.DataIntegrityViolationException ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				import   org.springframework.stereotype.Service ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				import   org.springframework.transaction.annotation.Isolation ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				import   org.springframework.transaction.annotation.Propagation ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				import   org.springframework.transaction.annotation.Transactional ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				import   searchengine.config.SitesList ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				import   searchengine.model.Link ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				import   searchengine.model.SiteEntity ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				import   searchengine.model.PageEntity ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				import   searchengine.model.StatusType ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				import   searchengine.repository.PageRepository ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				import   searchengine.repository.SiteRepository ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				import   java.net.URI ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				import   java.net.URISyntaxException ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				import   java.net.URLEncoder ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				import   java.nio.charset.StandardCharsets ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				import   java.time.LocalDateTime ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				import   java.util.HashSet ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				import   java.util.Set ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				import   java.util.concurrent.ConcurrentHashMap ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				import   java.util.regex.Pattern ; 
 
			
		 
		
	
	
		
			
				
					
					
						
					 
				
			
			 
			 
			
				@@ -32,164 +18,78 @@ import java.util.regex.Pattern;
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				@Service 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				@RequiredArgsConstructor 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				public   class  IndexingServiceImpl   implements   IndexingService   { 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				     private   static   final   Logger   logger   =   LoggerFactory . getLogger ( IndexingServiceImpl . class ) ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				     private   boolean   indexingIsRunning   =   false ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				     private   final   SitesList   sitesList ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				     private   final   SiteRepository   siteRepository ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				     private   final   PageRepository   pageRepository ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				     @Override 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				     @Transactional ( propagation   =   Propagation . REQUIRED ,   isolation   =   Isolation . READ_COMMITTED ,   noRollbackFor   =   Exception . class ) 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				     public   void   startIndexing ( )   { 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				         if   ( indexingIsRunning )   { 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				             logger . info ( " Индексация уже запущена " ) ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				             System . out . println ( " Индексация уже запущена " ) ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				             return ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				         } 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				         indexingIsRunning   =   true ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				         // Выводим список сайтов для индексации 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				         logger . info ( " Список сайтов для индексации: " ) ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				         System . out . println ( " Список сайтов для индексации: " ) ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				         sitesList . getSites ( ) . forEach ( site   - > 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				                 logger . info ( " URL: {}, Название: {} " ,   site . getUrl ( ) ,   site . getName ( ) ) 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				                 System . out . println ( " URL:  "   +   site . getUrl ( )   +   " , Название:  "   +   site . getName ( ) ) 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				         ) ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				         // Начинаем парсинг первого сайта 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				         String   startUrl   =   sitesList . getSites ( ) . get ( 0 ) . getUrl ( ) ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				         String   siteName   =   sitesList . getSites ( ) . get ( 0 ) . getName ( ) ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				         logger . info ( " Начинаем парсинг сайта {} ({}) " ,    siteName ,   startUrl ) ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				         System . out . println ( " Начинаем парсинг сайта "   +    siteName   +   "  ( "   +   startUrl   +   " ) " ) ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				         Set < URI >   visitedLinks   =   ConcurrentHashMap . newKeySet ( ) ;   // Н а б о р   для отслеживания посещенных URL 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				         Set < Link >   allLinks   =   ConcurrentHashMap . newKeySet ( ) ;   // Н а б о р   для хранения всех ссылок 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				         try   { 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				             URI   startUri   =   new   URI ( startUrl ) ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				             logger . info ( " === Начало индексации {} ({}) ===  " ,   siteName ,   startUri ) ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				             // Удаляем существующие данные по этому сайту 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				             SiteEntity   site   =   siteRepository . findByUrl ( startUrl ) ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				             if   ( site   ! =   null )   { 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				                 logger . info ( " Найден существующий SiteEntity с   ID: {} " ,   site . getId ( ) ) ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				                 pageRepository . deleteBySite ( site ) ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				                 logger . info ( " Удалены все PsgeEntity для SiteEntity с   ID: {} " ,   site . getId ( ) ) ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				                 siteRepository . delete ( site ) ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				                 logger . info ( " Удален SiteEntity с   ID: {} " ,   site . getId ( ) ) ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				             } 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				             // Создаем новую запись в таблице site с о   статусом INDEXING 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				             site   =   new   SiteEntity ( ) ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				             site . setName ( siteName ) ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				             site . setUrl ( startUrl ) ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				             site . setStatus ( StatusType . INDEXING ) ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				             site . setStatus_time ( LocalDateTime . now ( ) ) ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				             site   =   siteRepository . save ( site ) ;   // Сохраняем и обновляем объект 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				             logger . info ( " Создана новая запись в таблице site с   ID: {} " ,   site . getId ( ) ) ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				             System . out . printf ( " \ n === Начало индексации %s (%s) === \ n " ,   siteName ,   startUri ) ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				             Link   rootLink   =   new   Link ( startUri ,   null ) ;   // Создаем корневой Link 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				             all Links . add ( root Link) ;   // Добавляем корневую ссылку во множество всех ссылок  
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				             parse ( rootLink ,   site ,   visitedLinks ,   allLinks ) ;   // Запуск парсинга 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				             // Обновляем статус сайта на INDEXED 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				             site . setStatus ( StatusType . INDEXED ) ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				             site . setStatus_time ( LocalDateTime . now ( ) ) ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				             siteRepository . save ( site ) ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				             logger . info ( " Статус сайта обновлен на INDEXED с   ID: {} " ,   site . getId ( ) ) ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				             parse ( root Link,   visited Links ) ;   // Запуск парсинга  
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				         }   catch   ( URISyntaxException   e )   { 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				             logger . error ( " Некорректный URL: {}  " ,   startUrl ,   e  ); 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				             handleIndexingError ( startUrl ,   " Некорректный URL:  "   +   startUrl ) ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				             System . out . println ( " Некорректный URL:  "   +   startUrl ) ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				         }   catch   ( InterruptedException   e )   { 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				             logger . error ( " Индексация была прервана: {}  " ,   e . getMessage ( ) ,   e  ); 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				             handleIndexingError ( startUrl ,   " Индексация была прервана:  "   +   e . getMessage ( ) ) ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				         }   catch   ( Exception   e )   { 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				             logger . error ( " Произошла ошибка при индексации: {} " ,   e . getMessage ( ) ,   e ) ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				             handleIndexingError ( startUrl ,   " Произошла ошибка при индексации:  "   +   e . getMessage ( ) ) ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				             System . out . println ( " Индексация была прервана:  "   +   e . getMessage ( ) ) ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				             Thread . currentThread ( ) . interrupt ( ) ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				         }   finally   { 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				             indexingIsRunning   =   false ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				             logger . info ( " === Индексация завершена === " ) ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				             logger . info ( " В с е г о   страниц проиндексировано: {} " ,   visitedLinks . size ( ) ) ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				             System . out . println ( " \ n === Индексация завершена ===" ) ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				             System . out . println ( " В с е г о   страниц проиндексировано: "   +   visitedLinks . size ( ) ) ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				         } 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				     } 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				     private   void   parse ( Link   link ,   SiteEntity   site ,   Set < URI >   visitedLinks ,   Set < Link >   all Links )   throws   InterruptedException   { 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				     private   void   parse ( Link   link ,   Set < URI >   visited Links )   throws   InterruptedException   { 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				         // Добавляем текущий URL в visitedLinks до начала обработки 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				         if   ( ! visitedLinks . add ( link . uri ( ) ) )   { 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				             logger . debug ( " URL уже был обработан: {} " ,   link . uri ( ) ) ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				             return ;   // Если URL уже был обработан, выходим 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				         } 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				         // Обновляем время статуса  
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				         site . setStatus_time ( LocalDateTime . now ( ) ) ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				         siteRepository . save ( site ) ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				         // Задержка для соблюдения правил robots.txt 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				         try   { 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				             Thread . sleep ( ( long )   ( 50   +   ( Math . random ( )   *   150 ) ) ) ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				         }   catch   ( InterruptedException   e )   { 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				             logger . error ( " Парсинг был прерван: {} " ,   e . getMessage ( ) ,   e ) ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				             Thread . currentThread ( ) . interrupt ( ) ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				             throw   new   RuntimeException ( " Парсинг был прерван:  "   +   e . getMessage ( ) ,   e ) ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				         } 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				         logger . info ( " Парсим страницу: {} " ,   link . uri ( ) ) ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				         // Задержка для защиты от блокировки  
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				         Thread . sleep ( ( long )   ( 50   +   ( Math . random ( )   *   150 ) ) ) ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				         System . out . println ( " Парсим страницу:  "   +   link . uri ( ) ) ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				         // Добавляем дочерние ссылки 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				         try   { 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				             addChildLinks ( link ,   site ,   visitedLinks ,   allLinks ) ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				         }   catch   ( Exception   e )   { 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				             logger . error ( " Ошибка при добавлении дочерних ссылок для {}: {} " ,   link . uri ( ) ,   e . getMessage ( ) ,   e ) ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				             throw   e ;   // Пробрасываем исключение дальше 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				         } 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				         addChildLinks ( link ,   visitedLinks ) ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				         // Рекурсивно обрабатываем дочерние ссылки 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				         for   ( Link   child   :   new   HashSet < > ( allLinks ) )   {   // Создаем копию множества для итерации 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				             if   ( ! visitedLinks . contains ( child . uri ( ) ) )   { 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				                 try   { 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				                     parse ( child ,   site ,   visitedLinks ,   allLinks ) ;  
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				                 }   catch   ( InterruptedException   e )   { 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				                     logger . error  ( " Парсинг был прерван: {}  " ,   e . getMessage ( ) ,   e  ); 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				                     Thread . currentThread ( ) . interrupt ( ) ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				                     throw   new   RuntimeException ( " Парсинг был прерван:  "   +   e . getMessage ( ) ,   e ) ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				                 }   catch   ( Exception   e )   { 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				                     logger . error ( " Произошла ошибка при парсинге {}: {} " ,   child . uri ( ) ,   e . getMessage ( ) ,   e ) ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				                 } 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				         link . children ( ) . forEach ( child   - >   { 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				             try   { 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				                 parse ( child ,   visitedLinks ) ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				            }   catch   ( InterruptedException   e )   {  
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				                 Thread . currentThread ( ) . interrupt ( ) ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				                throw   new   RuntimeException  ( " Парсинг был прерван:  "   +   e . getMessage ( ) ) ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				             } 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				         } 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				         } ) ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				     } 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				     private   void   addChildLinks ( Link   link ,   SiteEntity   site ,   Set < URI >   visitedLinks ,   Set < Link >   all Links )   { 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				     private   void   addChildLinks ( Link   link ,   Set < URI >   visited Links )   { 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				         try   { 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				             logger . debug ( " Пытаемся получить страницу: {} " ,   link . uri ( ) ) ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				             Document   document   =   Jsoup . connect ( link . uri ( ) . toString ( ) ) 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				                     . userAgent ( " Mozilla/5.0 " ) 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				                     . referrer ( " https://www.google.com " ) 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				                     . get ( ) ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				             logger . debug ( " Страница успешно получена: {} " ,   link . uri ( ) ) ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				             // Проверяем, что site не равен null 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				             if   ( site   = =   null )   { 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				                 throw   new   IllegalStateException ( " SiteEntity не может быть null " ) ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				             } 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				             // Получаем путь 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				             String   path   =   link . uri ( ) . getPath ( ) ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				             if   ( path   = =   null   | |   path . isEmpty ( ) )   { 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				                 path   =   " / " ;   // Устанавливаем корневой путь, если он пустой 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				             } 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				             PageEntity   existingPage   =   pageRepository . findBySiteAndPath ( site ,   path ) ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				             if   ( existingPage   = =   null )   { 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				                 // Сохраняем страницу в базу данных 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				                 PageEntity   page   =   new   PageEntity ( ) ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				                 page . setSite ( site ) ;   // Устанавливаем связь с   SiteEntity 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				                 page . setPath ( path ) ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				                 page . setCode ( document . connection ( ) . response ( ) . statusCode ( ) ) ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				                 page . setContent ( document . outerHtml ( ) ) ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				                 pageRepository . save ( page ) ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				                 logger . info ( " Сохранена страница: {} " ,   link . uri ( ) ) ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				             }   else   { 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				                 logger . warn ( " Страница уже существует: {} " ,   link . uri ( ) ) ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				             } 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				             document . select ( " a[href] " ) . forEach ( element   - >   { 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				                 String   hrefStr   =   element . attr ( " href " ) . strip ( ) ; 
 
			
		 
		
	
	
		
			
				
					
					
						
					 
				
			
			 
			 
			
				@@ -207,46 +107,34 @@ public class IndexingServiceImpl implements IndexingService {
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				                     // Проверяем, что ссылка корректна 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				                     if   ( isCorrectUrl ( link . uri ( ) ,   href ,   visitedLinks ) )   { 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				                         L ink  childLink   =   new   Link ( href ,   link ) ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				                         allLinks . add ( childLink ) ;   // Добавляем дочернюю ссылку в список всех ссылок 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				                         logger . debug ( " Добавлена дочерняя ссылка: {} " ,   childLink . uri ( ) ) ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				                         l ink. addChild ( href ) ;   // Используем метод addChild из класса Link 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				                     } 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				                 }   catch   ( Exception   e )   { 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				                     logger . warn ( " Некорректная ссылка: {} " ,   hrefStr ,   e ) ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				                     // Игнорируем некорректные URL без вывода сообщений 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				                 } 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				             } ) ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				         }   catch   ( HttpStatusException   e )   { 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				             logger . warn ( " HTTP ошибка при добавлении дочерних ссылок: Status={}, URL={} " ,   e . getStatusCode ( ) ,   e . getUrl ( ) ) ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				         }   catch   ( DataIntegrityViolationException   e )   { 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				             logger . error ( " Ошибка целостности данных при сохранении страницы: {} " ,   e . getMessage ( ) ) ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				             throw   e ;   // Пробрасываем исключение дальше 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				         }   catch   ( Exception   e )   { 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				             logger . error ( " Ошибка при добавлении дочерних ссылок: {} " ,   e . getMessage ( ) ,   e ) ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				             throw   new   RuntimeException ( " Ошибка при добавлении дочерних ссылок " ,   e ) ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				             // Игнорируем ошибки без вывода сообщений 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				         } 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				     } 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				     private   URI   normalizeUri ( URI   href )   { 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				         try   { 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				             String   path   =   href . getPath ( ) ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				             if   ( path   = =   null   | |   path . isEmpty ( ) )   { 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				                 path   =   " /  ";   // Устанавливаем корневой путь, если он пустой  
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				             String   path   =   href . getPath ( ) ;   // Получаем путь 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				             if   ( path   = =   null )   { 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				                 path   =   " " ;   // Если путь равен null, заменяем на пустую строку  
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				             }   else   { 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				                 path   =   path . replaceAll ( " /+$ " ,   " " ) ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				                 if   ( path . isEmpty ( ) )   { 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				                     path   =   " / " ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				                 } 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				                 path   =   path . replaceAll ( " /+$ " ,   " " ) ;   // Убираем завершающие слэши 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				             } 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				             return   new   URI ( 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				                     href . getScheme ( ) , 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				                     href . getAuthority ( ) , 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				                     path , 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				                     path ,   // Используем обработанный путь 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				                     null , 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				                     href . getFragment ( ) 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				             ) ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				         }   catch   ( URISyntaxException   e )   { 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				             logger . warn ( " Некорректный URL: {} " ,   href ,   e ) ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				             return   href ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				             return   href ;   // В   случае ошибки возвращаем исходный URI 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				         } 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				     } 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				
 
			
		 
		
	
	
		
			
				
					
					
						
					 
				
			
			 
			 
			
				@@ -254,13 +142,11 @@ public class IndexingServiceImpl implements IndexingService {
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				         // Проверка на некорректные протоколы 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				         String   hrefStr   =   href . toString ( ) ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				         if   ( hrefStr . startsWith ( " javascript: " )   | |   hrefStr . startsWith ( " mailto: " )   | |   hrefStr . startsWith ( " tel: " ) )   { 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				             logger . debug ( " Некорректный протокол: {} " ,   hrefStr ) ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				             return   false ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				         } 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				         // Проверка на принадлежность тому же домену 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				         if   ( href . getHost ( )   = =   null   | |   ! href . getHost ( ) . equals ( baseUri . getHost ( ) ) )   { 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				             logger . debug ( " Ссылка не принадлежит тому же домену: {} " ,   hrefStr ) ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				             return   false ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				         } 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				
 
			
		 
		
	
	
		
			
				
					
					
						
					 
				
			
			 
			 
			
				@@ -268,25 +154,10 @@ public class IndexingServiceImpl implements IndexingService {
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				         Pattern   patternNotFile   =   Pattern . compile ( " ( \\ S+( \\ .(?i)(jpg|png|gif|bmp|pdf|php|doc|docx|rar))$) " ) ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				         Pattern   patternNotAnchor   =   Pattern . compile ( " #([ \\ w \\ -]+)?$ " ) ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				         if   ( href . isOpaque ( )   | |   patternNotFile . matcher ( hrefStr ) . find ( )   | |   patternNotAnchor . matcher ( hrefStr ) . find ( ) )   { 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				             logger . debug ( " Ссылка на файл или якорь: {} " ,   hrefStr ) ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				             return   false ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				         } 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				         // Проверка на уже посещенные ссылки 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				         return   ! visitedLinks . contains ( href ) ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				     } 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				     private   void   handleIndexingError ( String   startUrl ,   String   errorMessage )   { 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				         SiteEntity   site   =   siteRepository . findByUrl ( startUrl ) ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				         if   ( site   ! =   null )   { 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				             site . setStatus ( StatusType . FAILED ) ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				             site . setLast_error ( errorMessage ) ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				             site . setStatus_time ( LocalDateTime . now ( ) ) ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				             siteRepository . save ( site ) ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				             logger . error ( " Ошибка индексации для сайта {}: {} " ,   startUrl ,   errorMessage ) ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				         }   else   { 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				             logger . error ( " Н е   удалось найти SiteEntity для URL: {}" ,   startUrl ) ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				         } 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				         logger . error ( errorMessage ) ; 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				     } 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				}