zetlnd

Untitled

Oct 20th, 2025
20
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 7.76 KB | None | 0 0
  1. (async () => {
  2. // --- НАСТРОЙКИ ---
  3. // Задержка между запросами к страницам (в миллисекундах)
  4. const DELAY_BETWEEN_REQUESTS = 1000; // 1 секунда
  5. const PAGINATION_SELECTOR = 'p.small a.pg'; // Селектор для пагинации
  6. const TOPIC_SELECTOR = 'a.torTopic'; // Селектор для тем
  7. // -----------------
  8.  
  9. console.log('%cЗапуск парсера тегов...', 'color: #28a745; font-size: 16px; font-weight: bold;');
  10.  
  11. /**
  12. * Фильтрует и нормализует тег.
  13. * @param {string} tag - Исходная строка тега.
  14. * @returns {string|null} - Возвращает очищенный тег или null, если тег нужно отбросить.
  15. */
  16. const normalizeAndFilterTag = (tag) => {
  17. let cleanedTag = tag.trim().replace(/\s*<wbr>|/g, '');
  18.  
  19. const BANNED_PATTERNS = [
  20. /^\d{4}(\s*г\.?)?$/, // Годы: 2025, 1998 г.
  21. /^v?(\d+\.)+[\w\s.-]*$/, // Версии: v0.1.2, 1.0, 0.5b, 1.0 Beta
  22. /^\d+(\.\d+)?$/, // Числа: 0.21, 1.0, 5
  23. /^(ch|ep|act|vol|part|s|season|день)\s*\.?\s*\d+.*/i, // Маркеры: Ch. 1, Ep. 5
  24. /^(rus|eng|jap|chi|kor|multi|ger|fra|ita|esp)$/i, // Языки
  25. /^(uncen|cen|ptcen)$/i, // Цензура
  26. /^(cd|dvd|iso|apk)$/i, // Типы файлов/носителей
  27. /\b(walkthrough|save|mod|dlc|fix|beta|alpha|demo|final|extra|repack|steam|gog|rus|eng)\b/i // Служебные слова
  28. ];
  29.  
  30. for (const pattern of BANNED_PATTERNS) {
  31. if (pattern.test(cleanedTag)) return null;
  32. }
  33.  
  34. if (cleanedTag.length < 2) return null;
  35.  
  36. // Нормализация регистра, сохраняя акронимы
  37. if (cleanedTag.toUpperCase() === cleanedTag) {
  38. return cleanedTag; // 'RPG', 'BDSM'
  39. }
  40. if (cleanedTag.toLowerCase() === 'jrpg') {
  41. return 'jRPG';
  42. }
  43. return cleanedTag.charAt(0).toUpperCase() + cleanedTag.slice(1).toLowerCase();
  44. };
  45.  
  46. /**
  47. * Извлекает теги со страницы и добавляет их в общую карту уникальных тегов.
  48. * @param {string} htmlText - HTML-код страницы.
  49. * @param {Map<string, string>} uniqueTagsMap - Карта для хранения уникальных тегов.
  50. * @returns {number} - Количество новых добавленных тегов.
  51. */
  52. const extractTagsFromHtml = (htmlText, uniqueTagsMap) => {
  53. const parser = new DOMParser();
  54. const doc = parser.parseFromString(htmlText, 'text/html');
  55. const topicLinks = doc.querySelectorAll(TOPIC_SELECTOR);
  56. let newTagsCount = 0;
  57.  
  58. topicLinks.forEach(link => {
  59. const title = link.textContent;
  60. const matches = title.match(/\[(.*?)\]/g);
  61.  
  62. if (matches) {
  63. matches.forEach(match => {
  64. const content = match.slice(1, -1).trim();
  65. if (content.includes(',')) {
  66. content.split(',').forEach(rawTag => {
  67. const processedTag = normalizeAndFilterTag(rawTag);
  68. if (processedTag) {
  69. const key = processedTag.toLowerCase();
  70. if (!uniqueTagsMap.has(key)) {
  71. uniqueTagsMap.set(key, processedTag);
  72. newTagsCount++;
  73. }
  74. }
  75. });
  76. }
  77. });
  78. }
  79. });
  80. return newTagsCount;
  81. };
  82.  
  83. /**
  84. * Генерирует полный список URL всех страниц пагинации.
  85. * @returns {string[]} - Массив URL.
  86. */
  87. const getAllPageUrls = () => {
  88. const pageLinks = Array.from(document.querySelectorAll(PAGINATION_SELECTOR));
  89. let maxPage = 1;
  90. let itemsPerPage = 50;
  91. let baseUrl = window.location.href;
  92.  
  93. pageLinks.forEach(link => {
  94. const pageNum = parseInt(link.textContent, 10);
  95. if (!isNaN(pageNum) && pageNum > maxPage) maxPage = pageNum;
  96. });
  97.  
  98. if (maxPage > 1) {
  99. const firstLinkWithStart = pageLinks.find(link => new URL(link.href).searchParams.has('start'));
  100. if (firstLinkWithStart) {
  101. const sampleUrl = new URL(firstLinkWithStart.href);
  102. const startValue = parseInt(sampleUrl.searchParams.get('start'), 10);
  103. const pageNum = parseInt(firstLinkWithStart.textContent, 10);
  104. if (pageNum > 1) itemsPerPage = startValue / (pageNum - 1);
  105. sampleUrl.searchParams.delete('start');
  106. baseUrl = sampleUrl.href;
  107. }
  108. }
  109.  
  110. const allUrls = [];
  111. const baseUrlObj = new URL(baseUrl);
  112. baseUrlObj.searchParams.delete('start');
  113.  
  114. for (let i = 1; i <= maxPage; i++) {
  115. const url = new URL(baseUrlObj.href);
  116. const start = (i - 1) * itemsPerPage;
  117. if (start > 0) url.searchParams.set('start', start);
  118. allUrls.push(url.href);
  119. }
  120.  
  121. console.log(`Обнаружено ${maxPage} страниц. Генерируем все ссылки для анализа.`);
  122. return allUrls;
  123. };
  124.  
  125. /**
  126. * Основная функция-исполнитель.
  127. */
  128. const main = async () => {
  129. const allPages = getAllPageUrls();
  130. const uniqueTags = new Map();
  131. let processedPages = 0;
  132.  
  133. for (const url of allPages) {
  134. try {
  135. console.log(`Обработка страницы ${processedPages + 1} из ${allPages.length}: ${url}`);
  136. const response = await fetch(url);
  137. if (!response.ok) throw new Error(`Ошибка сети: ${response.statusText}`);
  138. const htmlText = await response.text();
  139. const newTagsCount = extractTagsFromHtml(htmlText, uniqueTags);
  140. processedPages++;
  141. console.log(`Найдено ${newTagsCount} новых уникальных тегов. Всего: ${uniqueTags.size}`);
  142. if (processedPages < allPages.length) {
  143. await new Promise(resolve => setTimeout(resolve, DELAY_BETWEEN_REQUESTS));
  144. }
  145. } catch (error) {
  146. console.error(`Не удалось обработать страницу ${url}:`, error);
  147. }
  148. }
  149.  
  150. console.log('%c====================================', 'color: #007bff; font-weight: bold;');
  151. console.log(`%cОбработка завершена! Найдено ${uniqueTags.size} уникальных тегов.`, 'color: #28a745; font-size: 16px; font-weight: bold;');
  152.  
  153. const sortedTags = Array.from(uniqueTags.values()).sort((a, b) => a.localeCompare(b));
  154. const resultString = sortedTags.join(', ');
  155.  
  156. console.log('%cРезультат (отсортирован и готов к копированию):', 'color: #17a2b8; font-size: 14px;');
  157. console.log(resultString);
  158.  
  159. try {
  160. await navigator.clipboard.writeText(resultString);
  161. console.log('%cРезультат скопирован в буфер обмена!', 'color: #28a745; font-weight: bold;');
  162. } catch (err) {
  163. console.error('Не удалось автоматически скопировать текст:', err);
  164. }
  165. };
  166.  
  167. await main();
  168.  
  169. })();
  170.  
  171.  
Add Comment
Please, Sign In to add comment