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