Files
crm.clientright.ru/court_search_function.js
Fedor 01c4fe80b5 chore: snapshot current working tree changes
Save all currently accumulated repository changes as a backup snapshot for Gitea so no local work is lost.
2026-03-26 14:19:01 +03:00

247 lines
11 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// JavaScript функция для поиска дела через страницу поиска суда
// Используется в n8n workflow ноде "ищем дело через поиск"
// Работает только для региональных судов (*.sudrf.ru)
export default async function ({ page, context }) {
// Получаем данные из переменных n8n workflow
const originalUrl = '{{ $json.link }}' || '{{ $json.url }}';
const case_number = '{{ $json.case_number }}' || '';
const uid = '{{ $json.uid }}' || '';
if (!originalUrl) throw new Error('❌ Не передан url');
if (!case_number && !uid) throw new Error('❌ Не передан номер дела или УИД для поиска');
const sleep = ms => new Promise(r => setTimeout(r, ms));
// Определяем тип суда по URL
const isRegionalCourt = /\.sudrf\.ru/.test(originalUrl) && !/mos-(gorsud|sud)\.ru/.test(originalUrl);
if (!isRegionalCourt) {
return {
url: originalUrl,
source: new URL(originalUrl).hostname,
status: 'error',
error_type: 'not_regional_court',
error_message: 'Поиск через страницу поиска поддерживается только для региональных судов',
found_url: null,
message: 'Не региональный суд'
};
}
// Установка заголовков и поведения браузера
await page.setViewport({ width: 1920, height: 1080 });
await page.setExtraHTTPHeaders({
"Referer": "https://sudrf.ru/",
"Origin": "https://sudrf.ru",
"Accept-Language": "ru,en;q=0.9",
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8",
"Upgrade-Insecure-Requests": "1",
});
await page.setUserAgent(
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36"
);
try {
// Извлекаем параметры из исходного URL
const urlObj = new URL(originalUrl);
const hostname = urlObj.hostname;
const protocol = urlObj.protocol;
// Извлекаем srv_num и delo_id из параметров URL
// Если исходный URL уже на страницу дела (name_op=case), извлекаем параметры оттуда
// Если исходный URL на страницу поиска (name_op=sf), используем его как есть
const srvNum = urlObj.searchParams.get('srv_num') || '1';
const deloId = urlObj.searchParams.get('delo_id') || '';
const nameOp = urlObj.searchParams.get('name_op') || '';
// Формируем URL страницы поиска
// Если исходный URL уже на страницу поиска - используем его
// Если на страницу дела - формируем URL поиска из тех же параметров
let searchUrl;
if (nameOp === 'sf') {
// Уже на странице поиска
searchUrl = originalUrl;
} else {
// Формируем URL страницы поиска из параметров исходного URL
searchUrl = `${protocol}//${hostname}/modules.php?name=sud_delo&srv_num=${srvNum}&name_op=sf${deloId ? `&delo_id=${deloId}` : ''}`;
}
// Переходим на страницу поиска (предполагаем, что капча уже проверена/решена отдельной нодой)
await page.goto(searchUrl, { waitUntil: "domcontentloaded", timeout: 30000 });
await sleep(500);
// Быстрая проверка капчи (если она всё ещё есть - возвращаем ошибку)
const hasCaptcha = await page.evaluate(() => {
const captchaSelectors = [
'img[src*="captcha"]',
'img[src*="recaptcha"]',
'.captcha',
'#captcha',
'iframe[src*="recaptcha"]',
'div[class*="captcha"]',
'div[id*="captcha"]'
];
return captchaSelectors.some(sel => document.querySelector(sel));
});
if (hasCaptcha) {
// Капча всё ещё присутствует - возвращаем ошибку
return {
url: originalUrl,
source: hostname,
status: 'error',
error_type: 'captcha_required',
error_message: 'Требуется решение капчи',
found_url: null,
message: 'На странице поиска требуется решение капчи. Сначала используйте ноду "проверяем капчу".'
};
}
// Закрыть баннеры cookies, если есть
try {
await page.waitForSelector("#cookie-disclaimer .cd-close-button, .cookie-accept, .cookie__close", { timeout: 2000 });
const btns = await page.$$("#cookie-disclaimer .cd-close-button, .cookie-accept, .cookie__close");
if (btns[0]) await btns[0].click();
} catch (_) {}
await sleep(300);
// Заполняем форму поиска
// Ищем поле для номера дела или УИД
const searchFields = await page.evaluate(() => {
const fields = [];
// Ищем input поля с подходящими именами
document.querySelectorAll('input[type="text"], input[type="search"]').forEach(input => {
const name = input.name || '';
const id = input.id || '';
const placeholder = (input.placeholder || '').toLowerCase();
const label = (input.closest('tr')?.querySelector('td:first-child')?.textContent || '').toLowerCase();
if (name.includes('case') || name.includes('delo') || name.includes('number') ||
name.includes('uid') || id.includes('case') || id.includes('delo') ||
placeholder.includes('номер') || placeholder.includes('дел') ||
label.includes('номер') || label.includes('дел')) {
fields.push({ name: name || id, type: 'name', selector: name ? `input[name="${name}"]` : `input#${id}` });
}
});
return fields;
});
// Заполняем поле поиска (приоритет: номер дела, затем УИД)
const searchValue = case_number || uid;
if (!searchValue) {
return {
url: originalUrl,
source: hostname,
status: 'error',
error_type: 'no_search_value',
error_message: 'Нет данных для поиска (номер дела или УИД)',
found_url: null,
message: 'Не указан номер дела или УИД для поиска'
};
}
if (searchFields.length === 0) {
return {
url: originalUrl,
source: hostname,
status: 'error',
error_type: 'search_form_not_found',
error_message: 'Не найдена форма поиска на странице',
found_url: null,
message: 'Не удалось найти поля формы поиска'
};
}
// Заполняем первое найденное поле
const fieldSelector = searchFields[0].selector;
await page.waitForSelector(fieldSelector, { timeout: 5000 });
await page.click(fieldSelector, { clickCount: 3 }); // Выделяем весь текст
await page.type(fieldSelector, searchValue, { delay: 50 }); // Уменьшена задержка
await sleep(300);
// Ищем и нажимаем кнопку поиска
const searchButtonClicked = await page.evaluate(() => {
const buttons = Array.from(document.querySelectorAll('input[type="submit"], button, input[type="button"]'));
const searchBtn = buttons.find(btn => {
const text = (btn.value || btn.textContent || '').toLowerCase();
return text.includes('найти') || text.includes('поиск') || text.includes('search') ||
text.includes('искать') || btn.type === 'submit';
});
if (searchBtn) {
searchBtn.click();
return true;
}
return false;
});
if (!searchButtonClicked) {
return {
url: originalUrl,
source: hostname,
status: 'error',
error_type: 'search_button_not_found',
error_message: 'Не найдена кнопка поиска',
found_url: null,
message: 'Не удалось найти кнопку поиска на странице'
};
}
// Ждём результатов поиска (используем более быстрый режим)
await page.waitForNavigation({ waitUntil: "domcontentloaded", timeout: 15000 }).catch(() => {});
await sleep(1000);
// Ищем ссылку на дело в результатах
const caseLink = await page.evaluate((searchValue) => {
// Ищем ссылки, которые содержат номер дела или УИД
const links = Array.from(document.querySelectorAll('a[href*="case_id"], a[href*="delo"], a[href*="name_op=case"]'));
for (const link of links) {
const href = link.href || link.getAttribute('href') || '';
// Проверяем, что ссылка ведёт на страницу дела
if (href.includes('name_op=case') || href.includes('case_id')) {
// Если href относительный, делаем его абсолютным
if (href.startsWith('/') || href.startsWith('modules.php')) {
return window.location.origin + (href.startsWith('/') ? href : '/' + href);
}
return href;
}
}
return null;
}, searchValue);
if (caseLink) {
return {
url: originalUrl,
source: hostname,
status: 'success',
error_type: null,
error_message: null,
found_url: caseLink,
message: 'Дело найдено через страницу поиска'
};
} else {
return {
url: originalUrl,
source: hostname,
status: 'error',
error_type: 'case_not_found',
error_message: 'Дело не найдено в результатах поиска',
found_url: null,
message: 'Не удалось найти дело в результатах поиска'
};
}
} catch (error) {
return {
url: originalUrl,
source: new URL(originalUrl).hostname,
status: 'error',
error_type: 'search_failed',
error_message: `Ошибка при поиске дела: ${error.message}`,
found_url: null,
message: `Ошибка при поиске: ${error.message}`
};
}
}